一、需求分析
-
在微信小程序开发中,避免不了表单,监听表单内容变化单个书写方法有太过于繁琐,故针对这个问题而做出的解决方法。
简单的提个例子:
用户选择商品时,需要强制用户选完商品的所有规格,才可提交数据(按钮变化,为选择时置灰等);
用户选择的这个值是否会有其他操作。或者正则校验、弹窗提示等;
二、实现原理
使用Object.defineProperty()劫持数据的写操作,在监听对象改变后执行传入的watchFun 。
watch.js
const observe = (obj, key, watchFun, deep, page) => {
let oldVal = obj[key];
// 如果监听对象是object类型并且指定deep(深度监听)
if (oldVal !== null && typeof oldVal === "object" && deep) {
// 递归子集,依次执行observe()
Object.keys(oldVal).forEach((item) => {
observe(oldVal, item, watchFun, deep, page);
});
}
// 使用Object.defineProperty()劫持数据的写操作,在监听对象改变后执行传入的watchFun
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
set(value) {
if (value === oldVal) return;
// 由于只在监听表单时的校验,所以直接赋值
oldVal = value;
watchFun.call(page, value, oldVal);
},
get() {
return oldVal;
},
});
};
export const setWatcher = (page) => {
// 页面里的data字段
const data = page.data;
// 页面里的watch字段
const watch = page.watch;
// 对watch里列举的每一个字段(需要监听的字段)执行observe()
Object.keys(watch).forEach((key) => {
let targetData = data;
const targetKey = key;
// 支持deep深度监听,使用deep时需要配合handler使用,否则直接编写函数
const watchFun = watch[key].handler || watch[key];
const deep = watch[key].deep;
observe(targetData, targetKey, watchFun, deep, page);
});
};
在formPage中使用
import { setWatcher } from "[path]/utils/watch";
// onload
onLoad(options) {
// 初始化监听器
setWatcher(this);
},
// watch监听器
watch: {
refundForm: {
handler(val) {
this.validate();
},
deep: true,
}
},
// 规则校验
validate(val){
// 在这里写校验和提示,当需要监听的字段发生改变时,触发此方法。
}
三、致谢
感谢大家的阅读,最近感情受挫,先辈是对的,程序员怎么能谈恋爱呢?是吧。现阶段封印加固,只埋头干事业了,希望大家也能大到令自己辉煌的高度。