背景
小程序中的表单提交,需要校验表单填写完成按钮才是可点击状态,一般做法是每个表单变化的时候都去看是不是所有都填完成,也就是需要在每个可输入的地方做处理,希望能像vue的计算属性一样,在计算属性里面完成计算,不用在每个字段变化时处理
实现
reactive.js
ini
let effectFunc = null
let bucket = new WeakMap()
export const reactive = (target) =>{
for (let key in target) {
if(target.hasOwnProperty(key)) {
const value = target[key]
if (value && typeof value === 'object') {
target[key] = reactive(value)
}
setReactive(target, key, target[key])
}
}
return target
}
export const setReactive = (target, pop, value) => {
let reactiveValue = value;
Object.defineProperty(target, pop, {
get () {
console.log('取值')
track(target, pop)
return reactiveValue
},
set(newValue) {
console.log('设置值')
if (newValue !== reactiveValue) {
reactiveValue = newValue;
trigger(target, pop);
}
}
})
}
const trigger = (target, key) => {
const mapBucket = bucket.get(target)
if (!mapBucket) return
const set = mapBucket.get(key)
if (set && set.size > 0) {
set.forEach(effect => {
effect()
})
}
}
const track = (target, key) => {
if (!effectFunc) return
let mapBucket = bucket.get(target)
if (!mapBucket) {
bucket.set(target, mapBucket = new Map())
}
let set = mapBucket.get(key)
if (!set) {
mapBucket.set(key, set = new Set())
}
set.add(effectFunc)
}
export const computed = (func) => {
let value;
let dirty = true;
const effect = () => {
dirty = true;
effectFunc = effect;
value = func();
return value;
};
const computedValue = {
get value() {
if (dirty) {
value = effect();
dirty = false;
}
return value;
},
};
effect();
return computedValue;
}
使用
kotlin
import {reactive} from './reactive'
data: {
test: reactive({
a: 2
})
}
onLoad: async function () {
console.log(this.data.test.a)
this.data.test.a = 7
this.setData({
[`test.a`]: 9
})
console.log(this.data.test.a)
}
问题
取值的时候能走get,设置值的时候不走set 自己仿写了一个极简Page
kotlin
class Page {
data = {}
constructor(options) {
this.data = options.data
if ('onload' in options && typeof options.onload === 'function') {
options.onload.call(this)
}
}
}
new Page({
data: reactive({person: {
age: 3,
a:5
}}),
onload() {
console.log('页面加载完成', this.data.person.age)
this.data.person.age = 6
}
})
发现set和get都是可以执行的,那应该就是小程序的内部实现机制的问题,也许可以拦截setData实现,下来研究
其他
-
为什么不用proxy
因为
Proxy
是 ECMAScript 6 标准的一部分,而一些老版本的小程序运行环境对ES6特性支持有限,像我的开发工具就不支持