公司使用微信小程序做了不少东西, 发现的痛点越来越多. 没有组件化, 配置繁锁, 生命周期名字不一. 基于它才有了 vue 系列的解决方案, 我在想, 能不能搞一套 React 的解决方案呢. 毕竟以 React 为技术栈的公司不在少数, 销路肯定很好.
我首先从定义组件着手. 微信小程序是存在自定义组件的机制, 但不能使用继承. 并且一个组件也拆得好碎, 分成四块. JS 定义, CSS, 模板与配置.
JS 定义
微信小程序是没有组件机制, 只是提供了一个工厂方法 Component 给你定义组件. 如果模糊来看, Page 也相当于组件, 因为它也有 data 与 setData 方法. 这相当于 React 的 state 与 setState.App 相当于 React 中的无状态组件, 它可以定义一个所有页面都能访问的 globalData 对象, 还有一些事件. 我们发现 App,Page,Component 的一些生命周期是与路由器挂钩的, 不像 React,React 只针对自身.
我们用 React 的概念来类似小程序吧, 这样对没有接触过小程序的同学比较好理解
- Component({ behaviors: [], // 相当于 mixin, 不建议使用
- properties: { // 相当于 propTypes
- myProperty: 1111
- myProperty2: 222
- },
- data: {}, // 相当于 state
- created(){}, //componentWillMount 或是 getDerivedStateFromProps
- attached(){}, //componentDidMount
- moved(){}, //componentDidUpdate 可以模拟它
- detached(){}, //componentWillUnmount
- methods: {// 放事件回调及其他方法, 已经 bind this, 现在也可以不用特意放在这个对象上, 这其实是早期抄袭 vue 的东西
- }
- })
小程序没有 shouldComponentUpdate, 我们可以对 setData 的第一个参数做一些手脚, 如果为 false, 返回一个空对象.
- this.setData( (function(self){
- // 调用原来的 shouldComponentUpdate 逻辑
- if(shouldComponentUpdate(self.properties, self.data ) ){
- return newData;
- } else{
- return {};
- }
- })(this),function(){
- // 调用原来的 componentDidUpdate 逻辑
- setStateCb && setStateCb.call(this)
- componentDidUpdate && componentDidUpdate.call(this)
- })
如此一来, React 的生命周期就能一一对上号了, 当然如果大家想一套代码共用 touch 与 weixin, 建议不要用 shouldComponentUpdate, 这个模拟成本很高, 可能与 React 的效果差距很大.
CSS
CSS, 在小程序中叫 WXSS, 是一个弱化版的 CSS. 文档中也介绍不要使用 id, 说明它无法做到 scoped. 但如果纯是写 CSS 没什么意义, 我们公司已经大量使用 less, sass 等预处理语言, 因此未来也会向这个方向发展.
模板
小程序将组件的模板独立出来, 使用经典的 JSP 风格嵌入变量, 还添加了 wx:if, wx:for 这些指令实现常规的 if, for 操作. 因此许多人就将它与 vue 类似起来. 但它与 vue 来比, 还是很弱, 首先, 它没有双向绑定 (美曰其名为单向流动), 其次事件绑定时只能使用方法名, 不能动态生成函数, 也不能指定一个函数, 再次也混杂了一些奇怪的标签, template, block, slot.template 是应该是 web component 的东西, block 是后端模块的东西, slot 是 vue 的.
- <view class="wrapper">
- <view > 这里是组件的内部节点 </view>
- <slot></slot>
- </view>
相当于 React 这样的代码
- <div class="wrapper">
- <div > 这里是组件的内部节点 </div>
- {this.props.children}
- </div>
相对于 React, vue, 它没有 ref 这种指令, 它是不想让我们得到元素节点, 但我们可以定义一些 data-* 属性, 然后在组件的 attached 钩子中通过 this.dataset 拿到它们. 但相当于 React, 我们是拿不到真正的 props. 在小程序中, properties 与 data 是同一个东西
- Component({
- data:{a: 1},
- attached: function(){
- console.log(this.data === this.properties) //true
- }
- })
jsx 中的 this.xxx http://jsx中的this.xxx , this.props.xxx 要统一进行去 "this." 操作, 这个用 babel 处理没什么难度.
配置
App,Page, Component 都有相应的 json 对象, 主要是定义弹窗的颜色, 页面的颜色及一些子组件的引用. 这些可以抽取成组件的静态属性, 这样代码就更加内聚.
在我动手之前, 业界其实已经有相关的方案出来, 比如 weact, taro 了. 我所组织的技术群, 也有一帮同好在做这东西, 看来潮流不可逆转, 小程序这种反人类的粗糙滥造之物必须再封装才方便我们迅速推进业务. 就像 sass, less 于之 css, typescript 于之 es5.
来源: https://juejin.im/entry/5b3b499d6fb9a04fd659296c