Riot.js 中文文档
本系列文章将有选择地翻译Riot.js 2.X 的英文文档,同时加入一点笔者自己的评价和使用心得。第一篇着重介绍Riot的基本特点
Riot.js 特点概述
-
自定义标签
Riot.js 支持在IE8+中自定义标签,并且这些标签是人类可读的
//demo 1 <todo> <!-- layout --> <h3>{ opts.title }</h3> <ul> <li each={ item, i in items }>{ item }</li> </ul> <form onsubmit={ add }> <input> <button>Add #{ items.length + 1 }</button> </form> <!-- logic --> <script> this.items = [] add(e) { var input = e.target[0] this.items.push(input.value) input.value = '' } </script> </todo>
标签的命名由你决定
<body> <h1>Acme community</h1> <forum-header/> <forum-content> <forum-threads/> <forum-sidebar/> </forum-content> <forum-footer/> <script>riot.mount('*', { api: forum_api })</script></body>
这语法就像React+Polymer,嗯,不过学习曲线非常小。标签的属性可以用一种很干净的方法加进去。
-
Virtual DOM
虚拟DOM是React这类框架提供的重要特性之一,Riot.js也提供了这个特性的一部分功能
-
和React一样,任何DOM操作都将进行比对后插入真实的DOM,保证DOM操作数量最小化
-
单向响应的数据流,只能从父节点向子节点传递
-
大部分表达式都可以通过(服务器)预编译并缓存来提高性能
-
生命周期事件,可以控制整个流程
-
贴近标准
Riot.js有一些和其他框架不同的地方
-
没有单独定义一套事件系统
-
完美支持IE8
-
渲染过的DOM可以被其他库100%控制
-
没有定义HTML根元素(笔者注,这里应该是指Angular的ngBody),也没有使用data-属性
-
懒人专用语法
Riot.js的一个设计目标是用尽可能小的语法改动来实现强大的功能
-
很快捷的基本语法:class={ enabled: is_enabled, hidden: hasErrors() }
-
没有React那额外的render、state、construtor什么什么的
-
要插入一个属性?Add #{ items.length + 1 } or class="item { selected: flag }"
-
在预编译之前用<script>标签来包裹JS代码,可有可无(笔者注,只能在额外的需要预编译的.tag文件中这么用)
-
可以用ES6、TypeScript、CoffeeScript或者其他你喜欢的JS扩展语言
-
体积小但功能全
Riot.js比起React、Ploymer什么的体积小的多的多(压缩后不超过5K),但提供了大部分常用的功能
像事件库、路由之类的,用来创建 Reactive 的用户界面
-
细节特性
-
Riot.js不像React,是基于DOM而不是基于字符串的,初始化组件时,Riot会遍历一课DOM树,然后从树中提出表达式并放进一个数组,每个表达式都有一个指向DOM节点的“指针”,每次运行这些表达式其实是先计算这些表达式再和DOM比较,当某个值改变的时候那个DOM节点也会改变。也可以认为Riot有一个“虚拟DOM”,只是简单的多(笔者注,由于Riot没有组件机制,整个页面就是一个“组件”,如果页面DOM结构很大的话,性能会很差,因为它会遍历整个DOM,和Angular初始化时一样)。由于这些表达式很快速,并且能被缓存更新周期,所以做100或者1000个表达式几乎只要1ms。因为HTML布局在每次更新后会随机修改,所以React的同步算法是很复杂的,这是个很大的挑战,FB的工程师能搞定真的很厉害!我们认为可以进一步避免复杂的比较,Riot里面HTML结构是定死的,只有“loop”和条件能增加或者删除元素,比如,一个<div>是不能被转换成<label>的,Riot只会更新那些没有复杂的子树替换的表达式。
-
React只处理UI,专注一个点是很正确的决策。FB推荐开发者用Flux去结构化客户端代码,这是一种比框架的庞大的模式,让人脑洞大开。Riot只捆绑了一个自定义标签、一个事件触发器(叫Oservable)还有一个Router,我们相信这是客户端APP的基本模块,事件负责模块化,Router负责URL还有后退按钮(笔者注,Riot可没集成Pjax。。),自定义标签负责UI。就像Flux,Riot就是这么个灵活的、给开发者更多架构决策空间。亲们可以用Router和Oservable来做一个类似于Flux的架构
-
和Polymer比较起来,在概念上差不多,细节的差别还是很大滴。Riot只更新不得不被更新的、需要改动HTML展示数据的DOM节点;Polymer的语法更复杂;P导入独立组件时是这样的:link rel="import",P必须用XHRs去排列他们,这样很慢也很痛苦,Riot用script src 来导入,你可扩展Riot,把你常用的几个标签组合起来封装成新工具;P是用双向数据绑定的;P没法在服务器预编译。
-
最后扯一句,Riot比上面两个的体积小22倍
笔者注
从官网介绍来看Riot是很强大的,不过亲们要知道的是体积越少说明功能越简单,很多细节需要自己去增加,下面笔者列出一些相比React缺失的特性以及列出笔者认为合适的使用场景
-
Riot.js没有React最重要的“组件化”特性,甚至不是完整的MVP(整个就是一个M一个V一个P,没有分离代码的机制),自然也没有Props这类东西,所谓“单向数据流”,需要你自己扩展;另外,Riot中只能用Loop和Conditions来改动HTML
-
Riot.js 2.X开始不再注重“MVP”,这个特性几乎体现不出来了,Riot的模块化更多只是用不同“事件”来区分
-
Riot.js 的性能嘛。。在一个稍大的APP上其实势必React差一点的。。毕竟两个“虚拟DOM”是不同的实现
-
Riot.js很多“特性”都只是个规范(比如Router),并没有实现和封装,这需要你自己来,当然,插件机制还没有做好呢,目前说的“灵活”更多来自于Undefined,而非选择的多样化
所以可能的使用场景是:
-
一个简单的WebApp,没有太多的JS代码,也不是很关注“组件化”
-
简单的手机App,或者“无后台”的客户端WebApp(即服务器只传一堆数据,而渲染界面之类的工作全部交给客户端)
嗯,笔者一直在强调“小型”,因为除非你自己扩展Riot,否则这只能用在单人团队上。
当然Riot也有很多优秀的特性,官网的介绍里可没说
-
Riot.js 的“loop”特性非常适合新闻类APP等需要展示大量遍历和渲染List的场景
-
Riot.js 提供了类似JSX的JSHTMLCSS混写特性,只是JSX是把HTML写在JS里,而Riot.js是把JS插到HTML里。不用担心JS和HTML会黏起来,Riot.js提供了一套很简单的模板引擎用于分离JS和HTML