目录

  • 1监听函数实现
  • 2.页面Page重写(实现无需引入)
  • 3完整代码实现
  • 4微信小程序代码片段

大家都知道小程序其实和Vue的写法以及原理都存在很大的相同,但是里有watch监听可以监听data定义的数据,而小程序里并没有(其实小程序并不需要哈哈,大家可以想想。但是作为程序员总想凭什么没有!)。

**其实监听器的原理,就是将data中需监听的属性写在watch对象中,并给其提供一个方法,当被监听属性的值改变时,调用该方法。

所以很显然,我们需要用到Javascript中的Object.defineProperty()方法,来手动劫持对象的getter/setter 从而实现给对象赋值时(调用setter),执行watch对象中相对应的函数,达到监听效果。Object.defineProperty()不在这里详细介绍,还不会使用的童鞋速戳这里-> Object.defineProperty()介绍。Object.defineProperty()

1监听函数实现

function setWatcher(page) {let data = page.data;let watch = page.watch;Object.keys(watch).forEach(v => {let key = v.split('.'); // 将watch中的属性以'.'切分成数组let nowData = data; // 将data赋值给nowDatafor (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,则为undefineobserve(nowData, lastKey, watchFun, deep, page); // 监听nowData对象的lastKey})
};
function 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对象下的每一个keyobserve(val, childKey, watchFun, deep, page); // 递归调用监听函数})}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;},get: function () {return val;}})
};

2.页面Page重写(实现无需引入)

// 保存原生构造函数
const OldPage = Page;
Page = function (conf) {// 这里的conf就是Page函数的内容{data, onLoad, onShow, ...}// 重写onLoad方法,用一个变量保存旧的onLoad函数let oldonLoad = conf.onLoad; // 同理conf.onLoad = function() {//执行onLoad的默认事件 do something// *********************************************// 此处不能写成oldonLoad(),否则没有this,this.setData等方法为undefined。这里的this在Page构造函数实例化的时候才会指定// 在Page构造函数实例化的时候,小程序会将当前的Page对象的原型链(__proto__)增加很多方法,例如setData。当前的obj没有setDataoldonLoad.call(this)}return OldPage(conf); // 将原生的构造函数return出去保持页面函数正常执行
};

3完整代码实现

1.在utils文件夹创建Page.js

// Page.js
// 保存原生构造函数
const OldPage = Page;
function setWatcher(page) {let data = page.data;let watch = page.watch;Object.keys(watch).forEach(v => {let key = v.split('.'); // 将watch中的属性以'.'切分成数组let nowData = data; // 将data赋值给nowDatafor (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,则为undefineobserve(nowData, lastKey, watchFun, deep, page); // 监听nowData对象的lastKey})
};
function 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对象下的每一个keyobserve(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;},get: function () {return val;}})
};
// 还原上个页面的参数到 options, 并删除 options.params
const extractParams = function (query = {}) {  const { params } = query  let options = { ...query }  if (params !== undefined) {  options = {  ...options,  ...JSON.parse(decodeURIComponent(params)),  }  delete options.params  }  return options
}
Page = function (conf) {if (conf.watch) {// 设置了watch监听let oldonLoad = conf.onLoad;conf.onLoad = function(options = {}) {setWatcher(this)oldonLoad && oldonLoad.call(this, extractParams(options))}} else {}return OldPage(conf);
};
module.exports = {Page
}// 在app.js头部引入即可
let Page = require('./utils/page.js').Page// 在index.js使用
Page({data: {watchData: "",my: {name: 'yeshen',age: 18,hobby: ['girls', 'games'],info: {tag: "年轻的少年",like: {food: "鱼"}}},},watch: {'my': {handler(newValue, oldValue) {console.log(newValue, oldValue, '-----监听到数据变化')},deep: true}},onLoad: function () {this.setData({'my.age': "20"})setTimeout(() => {this.data.my.info.like.food = "肉肉"}, 1000)},
})

4微信小程序代码片段

!!!戳这里 =>

微信小程序实现watch监听,无需页面引入!!!相关推荐

  1. H5及微信小程序实测可用——监听手机返回键操作

    目录 1.自定义导航(只能拦截左上角返回) 2.内嵌H5实现拦截物理键返回(均可监听) 微信小程序开发过程中我们经常遇到需要监听点击左上角返回.手机物理返回键或者左滑返回的需求 微信原生是没有API支 ...

  2. 微信小程序实现watch监听数据变化

    起因:众所周知,微信小程序的数据监听器observers只能在自定义组件中使用,如果想要在页面中实现类似的功能,就只有通过其他的方法.其一就是通过模拟vue的watch来监听数据变化. 实现如下: 1 ...

  3. 微信小程序使用watch监听数据变化

    众所周知,Vue中,可以使用监听属性 watch来观察和响应 Vue 实例上的数据变化,那么小程序能不能实现这一点呢? 监听器的原理,是将data中需监听的数据写在watch对象中,并给其提供一个方法 ...

  4. 微信小程序全局分享转发实现-无需页面单独设置

    微信小程序没有自带全局分享设置,页面开启分享功能必须要在页面中定义分享事件函数onShareAppMessage(分享给朋友)和onShareTimeline(分享至朋友圈).如果项目中页面比较多,一 ...

  5. 微信小程序全局变量改变监听

    问题来源 最近工作需要写小程序页面,其中有个页面情况为:父页面中包含了一个组件页面,组件页面中又包含了另外一个组件页面.需求为:点击最后一个组件页面中的一个view,需要显示最外层父页面中的一个弹出层 ...

  6. 微信小程序实现数据监听

    Component({properties: {// 这里定义了innerText属性,属性值可以在组件使用时指定},data: {// 这里是一些组件内部数据//content: 'sdcedc', ...

  7. 微信小游戏的电量监听

    在说小游戏的电量监听事件之前,我想先提一下小程序的电量监听事件. 在微信小程序中,是没有电量监听事件的,因为小程序没有全屏,手机端的电量和wifi等信息一直可以看得到,所以小程序里就没有这样的api了 ...

  8. 微信小程序开发:学习笔记[8]——页面跳转及传参

    微信小程序开发:学习笔记[8]--页面跳转及传参 页面跳转 一个小程序拥有多个页面,我们可以通过wx.navigateTo推入一个新的页面.在首页使用2次wx.navigateTo后,页面层级会有三层 ...

  9. 解决微信小程序使用switchTab跳转后页面不刷新的问题

    解决微信小程序使用switchTab跳转后页面不刷新的问题 参考文章: (1)解决微信小程序使用switchTab跳转后页面不刷新的问题 (2)https://www.cnblogs.com/mmyk ...

最新文章

  1. DeepID3:Face Recognition with Very Deep Neural Networks
  2. 17、任务十六——事件委托机制、简单表单验证
  3. 文件 numpy_通过 Kaggle 入门 NumPyamp;Panda
  4. TikTok 英国业务亏损、苹果从中国应用商店下架近4万款游戏、Zoom 接受调查等|Decode the Week...
  5. 用Microwindows(Nano-X)编写中文程序
  6. java反射main方法参数注意
  7. java编程技巧_Java编程技巧
  8. HDFS教程(02)- HDFS命令汇总
  9. 开源面向对象数据库 db4o 之旅,第 1 部分: 初识 db4o
  10. Oracle VM VirtualBox 使用教程,说实话也就那样吧
  11. 《植物大战僵尸》游戏数据修改
  12. 计算机专业课题 结题报告,计算机结题报告.doc
  13. nRF24L01+ 数据手册
  14. [Acc]4379. 两个闹钟 暴力
  15. 2021年中国不锈钢行业发展现状及重点企业对比分析[图]
  16. 【GPGPU编程模型与架构原理】第一章 1.3 现代 GPGPU 产品
  17. [系统安全] 二十一.PE数字签名之(中)Signcode、PEView、010Editor、Asn1View工具用法
  18. 稀疏矩阵向量乘(SpMV)
  19. 图片瀑布流差异化设计尝试
  20. Android 编译打包的那些疑问

热门文章

  1. 微信支付服务器system error,微信企业支付--遇到不明确结果的err_code:SYSTEMERROR,NOT_FOUND...
  2. 大数据征信成撬动消费金融的支点?
  3. anaconda下使用python怎样实现图像增强_如何用anaconda进行python开发
  4. Android加载web页时有的手机会弹出手机自带的浏览器解决方法
  5. Dell inspiron 7580硬件升级_更换电池加内存条移动硬盘
  6. 714. [C++]买卖股票的最佳时机含手续费
  7. 两个usb摄像头通过hub连接电脑怎么同时独立显示_把电脑装进口袋是什么感觉?华硕VivoStick TS10多角度体验...
  8. 微软必应成功预测法国队夺冠
  9. Ubuntu18.04+ROS melodic 控制UR5机器人(持续更新)
  10. h5自动播放视频且有声音的办法