前一段时间,我写了两篇文章,一篇是对目前前端主流视图框架的思考,一篇是深入使用RxJS控制复杂业务逻辑的,在这两篇中,我分别提到:
期望在复杂业务逻辑方面使用RxJS,更好地进行抽象,但是视图上使用轻量MVVM以达到快速开发的目的。
目前VueJS中,如果要结合RxJS,可能需要手动订阅和取消订阅,写起来还是没有CycleJS方便。
最近,VueJS社区升级了vue-rx这个库,实现了比较方便地把VueJS和RxJS结合的能力。
我们来详细了解一下。
在视图上绑定Observable
VueJS本身不是基于RxJS这一套理念构建的,如果不借助任何辅助的东西,可能我们会需要干这么一些事情:
手动订阅某些Observable,在observer里面,把数据设置到Vue的data上
在视图销毁的时候,手动取消订阅
在业务开发中,我们最常用的是绑定简单的Observable,在vue-rx中,这个需求被很轻松地满足了。
与早期版本不同,vue-rx 2.0在Vue实例上添加了一个subscriptions属性,里面放置各种待绑定的Observable,用的时候类似data。
比如,我们可以这么用它:
rx-simple.vue
<template> <div> <h4>Single Value</h4> <div>{{single$}}</div> <h4>Array</h4> <ul> <li v-for="item of arr0$">{{item}}</li> </ul> <ul> <li v-for="item of arr1$">{{item}}</li> </ul> <h4>Interval</h4> <div>{{interval$}}</div> <h4>High-order</h4> <div>{{high$}}</div> </div> </template> <script> import { Observable } from 'rxjs/Observable' import 'rxjs/add/observable/of' import 'rxjs/add/observable/from' import 'rxjs/add/operator/toArray' import 'rxjs/add/observable/interval' import 'rxjs/add/observable/range' import 'rxjs/add/operator/map' import 'rxjs/add/operator/mergeAll' const single$ = Observable.of(Math.PI) const arr0$ = Observable.of([1, 1, 2, 3, 5, 8, 13]) const arr1$ = Observable.from([1, 1, 2, 3, 5, 8, 13]).toArray() const interval$ = Observable.interval(1000) const high$ = Observable.range(1, 5) .map(item => Observable.interval(item * 1000)) .mergeAll() export default { name: 'rx-simple', subscriptions: { single$, arr0$, arr1$, interval$, high$ } } </script>
这个demo里面,演示了四种不同的Rx数据形态。其中,single$和interval$虽然创建方式不同,但实际上用的时候是一样的,因为,对它们的订阅,都是取其最后一个值,这两者的区别只是,一个不变了,一个持续变,但界面展示的始终是最后那个值。
关于数组,初学者需要稍微注意一下,从同样的数组,分别通过Observable.of和Observable.from出来的形态是大为不同的:
of创建的这个,里面只有一个值,这个值是个数组,所以,订阅它,会得到一个数组
from创建的这个,里面有若干个值,每个值是由数组中的元素创建的,订阅它,会一次性得到多个值,但展示的时候只会有最后一个,因为前面的都被覆盖掉了
那么,这个high$代表什么呢?
range操作,创建了一个流,里面有多个简单数字
map操作,把这个流升级为二阶,流里面每个元素又是一个流
mergeAll操作,把其中的每个流合并,降阶为一阶流,流里面每个元素是个简单数字
如果说不mergeAll,直接订阅map出来的那个二阶流,结果是不对的,vue-rx只支持一阶订阅绑定,不支持把高阶流直接绑定,如果有业务需要,应当自行降阶,通过各种flat、concat、merge操作,变成一阶流再进行绑定。
将Vue $watcher转换为Observable
上面我们述及的,都是从Observable的数据到Vue的ReactiveSetter和Getter中,这条路径的操作已经很简便了,我们只需把Observable放在vue实例的subscriptions里面,就能直接绑定到视图。
但是,反过来还有一条线,我们可能会需要根据某个数据的变化,让这个数据进入一个数据流,然后进行后续运算。
例如:有一个num属性,挂在data上,还有一个数据num1,表达:始终比num大1这么一件事。
当然,我们是可以直接利用computed property去做这件事的,为了使得我们这个例子更有说服力,给它这个加一计算添加一个延时3秒,强行变成异步:始终在num属性确定之后,等3秒,把自己变成比num大1的数字。
这样,computed property就写不出来了,我们可能就要手动去$watch这个num,然后在回调方法中,去延时加一,然后回来赋值给num1。
在vur-rx中,提供了一个从$watch创建Observable的方法,叫做$watchAsObservable,我们来看看怎么用:
rx-watcher.vue