在原生小程序中使用VUE写法并支持(一)
前言
在之前我使用了defineProperty来构建了一个简单的vue-watch-like式监听属性,但是defineProperty的缺点也是显而易见的,它无法深度监听数组的变化,当数组长度被修改时或其他意外行为时,defineProperty无法准确监听到数据变化。 这一章我利用ES6中的proxy来从新写一个监听属性,并且不止于此,我打算构建成一个小程序中的vue-like框架。
相关资料 Proxy-MDN defineProperty-MDN
目标
构建一个小程序中的vue-like框架,使得使用这个库后可以让我们的前端人员在写原生小程序时,就跟写vue代码类似,可以使用相同的API并达到相同效果。 话不多说,开始。
第一步-解决setData
小程序中,渲染机制由setData触发,如果没有调用setData,即时改变了data中的值,页面也不会重新渲染,这点跟react很相似,react使用setState,而在vue中,单纯的给data中的属性赋值就会重新渲染页面,所以我们第一步要做的,就是解决setData,让开发人员在开发过程中,对于页面的修改只需要修改data中属性的值,而不用setData。 首先我们构建一个类库,在构造时接受2个参数,1.ctx上下文对象,也就是小程序单页面的this,2.一个属性对象,也就是我们接下来需要在里面放置的vue-like-api,眼下我们先构建一个监听属性。
class QVue{
constructor(ctx={},{watch={}}){
this.ctx = ctx;
this.watch = watch;
}
}
在QVue中放置对应的函数。
class QVue{
constructor(ctx={},{watch={}}){
this.ctx = ctx;
this.watch = watch;
}
mounted=()=>{
}
observer=()=>{
}
}
在监听者中通过proxy包装上下文中的data,包装过后的data是一个Proxy对象,当内部属性发生变化时,会触发get、set函数。我们可以用get拿到我们的旧值并保存,通过set拿到修改后的值。通过这两个函数,我们就可以把页面中的setData简化,当页面进行this.data.num=1这类赋值时,set方法就会触发并接收该属性最新的值,我们通过ctx上下文的setData,在set中调用渲染。 到这里 ,我们的第一步解决setData就算完成了,在页面中只要data中的值有变化都会重新触发页面渲染。
class QVue{
constructor(ctx={},{watch={}}){
this.ctx = ctx;
this.watch = watch;
}
mounted=()=>{
}
observer =(ctx,watch)=> {
ctx.data = new Proxy(ctx.data, {
get: function (_obj, _key,) {
this.oldValue = _obj[_key]
return _obj[_key]
},
set: function (_obj, _key, newVal) {
_obj[_key] = newVal
ctx.setData({
...ctx.data,
});
return true;
},
});
}
}
第二步-添加监听属性
这一步其实在上一章中就有实现,我们已经在第一步中包装了上下文的data并且监听到了每个属性的修改变动,那么下一步就是在监听到的时间中,调用传入的watch对象中的对应函数,并且把新值与旧值传递过去。
class QVue {
constructor(ctx={},{watch={}}){
this.ctx = ctx;
this.watch = watch;
this.mounted()
}
mounted=()=>{
const {ctx,watch} = this;
this.observer(ctx,watch)
}
observer =(ctx,watch)=> {
ctx.data = new Proxy(ctx.data, {
get: function (_obj, _key,) {
this.oldValue = _obj[_key]
return _obj[_key]
},
set: function (_obj, _key, newVal) {
_obj[_key] = newVal
ctx.setData({
...ctx.data,
},()=>{
watch[_key]&&watch[_key].call(ctx, newVal,this.oldValue)
});
return true;
},
});
}
}
在页面中使用 How to use
import QVue from "/QVue";
Page({
data: {
active: "",
},
onLoad: function (options) {
new QVue(this, {
watch: {
active: function (newVal) {
console.log('变化了,值是:',newVal);
},
},
});
this.active = 0
},
})
未完待续…
|