公司使用微信小程序做了不少东西,发现的痛点越来越多。没有组件化,配置繁锁,生命周期名字不一。基于它才有了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, this.props.xxx要统一进行去“this.”操作,这个用 babel 处理没什么难度。
配置
App,Page, Component都有相应的json对象,主要是定义弹窗的颜色,页面的颜色及一些子组件的引用。这些可以抽取成组件的静态属性,这样代码就更加内聚。
在我动手之前,业界其实已经有相关的方案出来,比如 weact, taro了。我所组织的技术群,也有一帮同好在做这东西,看来潮流不可逆转,小程序这种反人类的粗糙滥造之物必须再封装才方便我们迅速推进业务。就像sass, less于之css, typescript于之es5。