微信小程序实现watch属性监听数据变化
Vue 提供了一种通用的方式来观察和响应 Vue 实例上的数据变动:监听属性 watch。
虽然watch的滥用会导致性能不佳,但在一些情况下我们还是需要watch,使得代码更加简洁、逻辑更加清晰(其实就是嫌麻烦...)。
接下来我将逐步讲解微信小程序中如何实现一个监听器 watch,若想直接看最终代码,可直接滑动至底部。
监听器的原理,将data中需监听的属性写在watch对象中,并给其提供一个方法,当被监听属性的值改变时,调用该方法。
所以很显然,我们需要用到Javascript中的Object.defineProperty()方法,来手动劫持对象的getter/setter,从而实现给对象赋值时(调用setter),执行watch对象中相对应的函数,达到监听效果。Object.defineProperty()不在这里详细介绍,还不会使用的童鞋速戳这里-> Object.defineProperty()介绍。
首先,既然是微信小程序自定义watch属性,我建议直接将代码写在app.js内,需要使用的页面直接在onLoad()内调用getApp().setWatch(...)即可
// app.js /**
* 小程序初始化
*/
onLaunch(){...} /**
* 设置监听器
*/
setWatcher(data, watch) { // 接收index.js传过来的data对象和watch对象
Object.keys(watch).forEach(v => { // 将watch对象内的key遍历
this.observe(data, v,watch[v]); // 监听data内的v属性,传入watch内对应函数以调用
})
}, /**
* 监听属性 并执行监听函数
*/
observe(obj, key,watchFun) {
var val = obj[key]; // 给该属性设默认值
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
set: function(value) {
val = value;
watchFun(value,val); // 赋值(set)时,调用对应函数
},
get: function() {
return val;
}
})
}
此时在index.js中已经可以实现简单的属性监听: //index.js
Page({
data: {
name:"xuyang"
},
onLoad(){
getApp().setWatcher(this.data, this.watch); // 设置监听器
this.setData({
name:'lxm'
})
},
watch:{
name:function(newValue){
console.log(newValue); // name改变时,调用该方法输出新值。
}
}
})
我们可以看到,index页面启动后,name被赋值成'lxm',同时触发其setter,调用watch内的name()方法,控制台打印出 lxm。
是不是挺简单的呢?掌握了这一点,接下来的事情就好办多了。
我们知道,Vue中 watch对象内不光是能写name、age这类属性,还能用引号写出'my.name'、'my.age'这类属性,即对my对象下的name、age进行监听。 我们只需要改进一下setWatcher方法:
/**
* 设置监听器
*/
setWatcher(data, watch) {
Object.keys(watch).forEach(v => {
let key = v.split('.'); // 将watch中的属性以'.'切分成数组
let nowData = data; // 将data赋值给nowData
for (let i = 0; i < key.length - 1; i++) { // 遍历key数组的元素,除了最后一个!
nowData = nowData[key[i]]; // 将nowData指向它的key属性对象
}
let lastKey = key[key.length-1];
// 假设key==='my.name',此时nowData===data['my']===data.my,lastKey==='name'
this.observe(nowData, lastKey,watch[v]); // 监听nowData对象的lastKey
})
}
此时在index.js中可以这样写: //index.js Page({
data: {
my:{
name:"xuyang",
age:21
}
},
onLoad(){
getApp().setWatcher(this.data, this.watch);
this.data.my.name = 'lxm';
this.data.my.age = 2;
this.setData({
my: this.data.my
})
},
watch:{
'my.name':function(newValue){
console.log(newValue);
},
'my.age':function(newValue){
console.log(newValue);
}
}
})
控制台会打印出 lxm 和 2
现在我们又离成功更进了一步~ 接下来我们要实现Vue中的深度监听,即监听my对象即可监听它的内部所有属性以及属性的属性以及属性的属性的属性......并且监听函数的this要指向这个page里的this。
需要深度监听,Vue中的写法是
watch:{
my:{
handler(newValue){
// do something...
},
deep:true // 深度监听
}
}
我们需要修改一下app.js中的两个函数:
/**
* 设置监听器
*/
setWatcher(page) {
let data = page.data;
let watch = page.watch;
Object.keys(watch).forEach(v => {
let key = v.split('.'); // 将watch中的属性以'.'切分成数组
let nowData = data; // 将data赋值给nowData
for (let i = 0; i < key.length - 1; i++) { // 遍历key数组的元素,除了最后一个!
nowData = nowData[key[i]]; // 将nowData指向它的key属性对象
}
let lastKey = key[key.length - 1];
// 假设key==='my.name',此时nowData===data['my']===data.my,lastKey==='name'
let watchFun = watch[v].handler || watch[v]; // 兼容带handler和不带handler的两种写法
let deep = watch[v].deep; // 若未设置deep,则为undefine
this.observe(nowData, lastKey, watchFun, deep, page); // 监听nowData对象的lastKey
})
},
/**
* 监听属性 并执行监听函数
*/
observe(obj, key, watchFun, deep, page) {
var val = obj[key];
// 判断deep是true 且 val不能为空 且 typeof val==='object'(数组内数值变化也需要深度监听)
if (deep && val != null && typeof val === 'object') {
Object.keys(val).forEach(childKey=>{ // 遍历val对象下的每一个key
this.observe(val,childKey,watchFun,deep,page); // 递归调用监听函数
})
}
var that = this;
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
set: function(value) {
// 用page对象调用,改变函数内this指向,以便this.data访问data内的属性值
watchFun.call(page,value,val); // value是新值,val是旧值
val = value;
if(deep){ // 若是深度监听,重新监听该对象,以便监听其属性。
that.observe(obj, key, watchFun, deep, page);
}
},
get: function() {
return val;
}
})
}
其中需要特别注意,若是data中先声明一个对象userInfo = {},再给userInfo赋值一个对象(比如从服务器获取用户数据),则需要重新遍历监听才能实现深度监听,故需加上这段代码:
if(deep){ // 若是深度监听,重新监听该对象,以便监听其属性。
that.observe(obj, key, watchFun, deep);
}
此时index.js中需要深度监听的属性,可以这样写:
//index.js
Page({
data: {
my: {
name: 'xuyang',
age: 21,
hobby: ['girls', 'games']
},
nameInfo:{}
},
onLoad() {
getApp().setWatcher(this);
this.data.my.hobby[0] = 'study';
this.setData({
nameInfo:{name:'haha',sex:'boy'}
})
console.log(this.data)
},
watch: {
my:{
handler(newValue) {
console.log(newValue);
},
deep:true
}
}
})
微信小程序实现watch属性监听数据变化的更多相关文章
- 关于微信小程序使用watch监听数据变化的方法
众所周知,Vue中,可以使用监听属性 watch来观察和响应 Vue 实例上的数据变化,那么小程序能不能实现这一点呢? 监听器的原理,是将data中需监听的数据写在watch对象中,并给其提供一个方法 ...
- 微信小程序结合后台数据管理实现商品数据的动态展示、维护
微信小程序给我们提供了一个很好的开发平台,可以用于展现各种数据和实现丰富的功能,本篇随笔介绍微信小程序结合后台数据管理实现商品数据的动态展示.维护,介绍如何实现商品数据在后台管理系统中的维护管理,并通 ...
- 微信小程序通过api接口将json数据展现到小程序示例
这篇文章主要介绍了微信小程序通过api接口将json数据展现到小程序示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧实现知乎客户端的一个重要知识前提就是,要知道怎么通过 ...
- 微信小程序wx.request请求服务器json数据并渲染到页面
[原文出自]: https://blog.csdn.net/weixin_39927850/article/details/79766259 微信小程序的数据总不能写死吧,肯定是要结合数据库来做数据更 ...
- ESP32 BLE蓝牙 微信小程序通信发送大于20字符数据
由于微信小程序只支持BLE每次发送数据不大于20个字节,ESP32则有经典蓝牙.低功耗蓝牙两种模式. 要解决发送数据大于20个字节的问题,最简单实用的方式就是分包发送.如下图所示: 1.什么起始字符和 ...
- vue.js之过滤器,自定义指令,自定义键盘信息以及监听数据变化
一.监听数据变化 1.监听数据变化有两种,深度和浅度,形式如下: vm.$watch(name,fnCb); //浅度 vm.$watch(name,fnCb,{deep:true}); //深度监视 ...
- $scope.$watch()——监听数据变化
$scope.$watch(watchFn, watchAction, [deepWatch]):监听数据变化,三个参数 --watchFn:监听的对象,一个带有Angular 表达式或者函数的字符串 ...
- vue教程2-08 自定义键盘信息、监听数据变化vm.$watch
vue教程2-08 自定义键盘信息 @keydown.up @keydown.enter @keydown.a/b/c.... 自定义键盘信息: Vue.directive('on').keyCode ...
- 微信小程序关于tabbar点击切换数据不刷新问题
微信小程序中经常遇到的需求就是我提交了一个表单或者进行了一个操作,需要在我的个人中心页面中实时显示出来,但是小程序中的tabbar切换类似于tab切换 并不会进行页面刷新请求 所以总是会造成一些数据更 ...
随机推荐
- jar 解压war包到指定目录
用 jar -xvf .jar 命令默认解压到当前目录,想要解压到指定目录 需要使用unzip .jar -d 目录 如: unzip pay.war -d /home/zookeeper1/tes ...
- webstorm出现黑色块光标
取消掉此项对勾即可
- 二、docker学习笔记——安装redis
前提:打开powershell(管理员) 1.官网路径 按照官网的做了,但外网无法链接,只好换个做法. 2.docker pull redis 这下载的最新版redis 3.在docker上挂载文件夹 ...
- Python初学者第一天 Python安装及第一个Python程序
Python基础: 1day: 1.Python基础: A.编程语言介绍: a. 计算机只能理解0和1.编程即写一段按照一定规则写代码,让计算机帮你干活: b.机器语言:最底层的语言, ...
- python全栈学习笔记(三)网络基础之网络设备及架构介绍
- 玩转Windows/Linux tftp命令
tftp很好理解, 主要用来传文件, 下面以我的操作来谈谈tftp中最重要的几个命令. 一. Windows上的sftp命令(据说Linux上也是这样, 当然此处是指非嵌入式的Linux) 步骤: a ...
- 设计模式:外观(Facade)模式
设计模式:外观(Facade)模式 一.前言 外观模式是一种非常简单的模式,简单到我们经常都会使用,比如对于类A和B,如果两者需要交互,经过一定的处理过程才能实现某一个具体的功能,那么我们可以将这 ...
- TIAGO机器人传感器参数简介 手册翻译
本来认为这篇文章是最没人气的,竟然收到了回复,看来要继续更新本文了.留下笔者联系方式,邮箱leop22@163.com,欢迎邮件交流. 防止不良爬虫,原文链接:http://www.cnblogs.c ...
- 永中Office的ibus输入法问题
我在永中Office下无法调用ibus输入法,但是在其他窗口中都没有问题,如:gVIM,LeafPad,OpenOffice等等.我按照网上的方法在.bashrc文件中也添加了以下内容,可是还是不行. ...
- hdu-2879 hehe---积性函数
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2879 题目大意: he[n]为小于n且满足x^2 = x (mod n)的个数 hehe[n] = ...