用Vue.js实现监听属性的变化


Posted in Javascript onNovember 17, 2016

前言

创建 Vue 实例时,Vue 将遍历 data 的属性,通过 ES5 的 Object.defineProperty 将它们转为 getter/setter,在其内部 Vue 可以追踪依赖、通知变化。

const vm = new Vue({
 data: {foo: 1} // 'vm.foo' (在内部,同 'this.foo') 是响应的
})

观察属性变化

Vue 的实例提供了 $watch 方法,用于观察属性变化。

const vm = new Vue({
 data: {foo: 1}
})

vm.$watch('foo', function (newValue, oldValue) {
 console.log(newValue, oldValue) // 输出 2 1
 console.log(this.foo) // 输出 2
})

vm.foo = 2

当属性变化后,响应函数将会被调用,在其内部,this 自动绑定到 Vue 的实例 vm 上。

需要注意的是,响应是异步的。

如下:

const vm = new Vue({
 data: {foo: 1}
})

vm.$watch('foo', function (newValue, oldValue) {
 console.log('inner:', newValue) // 后输出 "inner" 2
})

vm.foo = 2
console.log('outer:', vm.foo) // 先输出 "outer" 2

通过 $watch Vue 实现了数据和视图的绑定。观察到数据变化,Vue 便异步更新 DOM ,在同一事件循环内,多次数据变化将会被缓存起来,在下次事件循环中,Vue 刷新队列并仅执行必要的更新。

如下:

const vm = new Vue({
 data: {foo: 1}
})

vm.$watch('foo', function (newValue, oldValue) {
 console.log('inner:', newValue) // 后只输出一次 "inner" 5
})

vm.foo = 2
vm.foo = 3
vm.foo = 4
console.log('outer:', vm.foo) // 先输出 "outer" 4
vm.foo = 5

计算属性

MV* 中,将 Model 层数据展现到 View,经常有复杂的数据处理逻辑,这种情况下,使用计算属性 (computed property) 更加明智。

const vm = new Vue({
 data: {
 width: 0,
 height: 0,
 },
 computed: {
 area () {
  let output = ''
  if (this.width > 0 && this.height > 0) {
  const area = this.width * this.height
  output = area.toFixed(2) + 'm²'
  }
  return output
 }
 }
})

vm.width = 2.34
vm.height = 5.67
console.log(vm.area) // 输出 "13.27m²"

在计算属性内部,this 自动绑定 vm,因此声明计算属性时需要避免使用箭头函数。

上例中,vm.widthvm.height 是响应的,vm.area 内部首次读取 this.width this.height 时,Vue 收集其做为 vm.area 的依赖,此后 vm.width vm.height 变化时,vm.area 重新求值。计算属性是基于它的依赖缓存,如果 vm.width vm.height 没有变化,多次读取 vm.area,会立即返回之前的计算结果,而不必再次求值。

同样由于 vm.widthvm.height 是响应的,在 vm.area 中可以将依赖的属性赋值给一个变量,通过读取变量来减少读取属性次数,同时解决在条件分支中,Vue 有时会无法收集到依赖的问题。

实现如下:

const vm = new Vue({
 data: {
 width: 0,
 height: 0,
 },
 computed: {
 area () {
  let output = ''
  const {width, height} = this
  if (width > 0 && height > 0) {
  const area = width * height
  output = area.toFixed(2) + 'm²'
  }
  return output
 }
 }
})

vm.width = 2.34
vm.height = 5.67
console.log(vm.area) // 输出 "13.27m²"

通过 ob.js 单独使用 Vue 的属性观察模块

为方便学习和使用,ob.js 将 Vue 中属性观察模块提取并封装了一下。

ob.js GitHub 地址:https://github.com/cnlon/ob.js

安装

npm install --save ob.js

观察属性变化

const target = {a: 1}
ob(target, 'a', function (newValue, oldValue) {
 console.log(newValue, oldValue) // 3 1
})
target.a = 3

添加计算属性

const target = {a: 1}
ob.compute(target, 'b', function () {
 return this.a * 2
})
target.a = 10
console.log(target.b) // 20

像声明 Vue 实例一样传入参数集合

const options = {
 data: {
 PI: Math.PI,
 radius: 1,
 },
 computed: {
 'area': function () {
  return this.PI * this.square(this.radius)
 },
 },
 watchers: {
 'area': function (newValue, oldValue) {
  console.log(newValue) // 28.274333882308138
 },
 },
 methods: {
 square (num) {
  return num * num
 },
 },
}
const target = ob.react(options)
target.radius = 3

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
纯JavaScript实现的兼容各浏览器的添加和移除事件封装
Mar 28 Javascript
使用JavaScript制作一个简单的计数器的方法
Jul 07 Javascript
JavaScript实现仿淘宝商品购买数量的增减效果
Jan 22 Javascript
jquery实现图片上传前本地预览功能
May 10 Javascript
Bootstrap的Refresh Icon也spin起来
Jul 13 Javascript
jquery实现刷新随机变化样式特效(tag标签样式)
Feb 03 Javascript
详解Sea.js中Module.exports和exports的区别
Feb 12 Javascript
微信小程序实现搜索历史功能
Mar 26 Javascript
详解JWT token心得与使用实例
Aug 02 Javascript
vue开发移动端底部导航条功能
Apr 08 Javascript
Vue实现导航栏菜单
Aug 19 Javascript
Python机器学习之决策树和随机森林
Jul 15 Javascript
JS实现类似51job上的地区选择效果示例
Nov 17 #Javascript
JS实现的适合做faq或menu滑动效果示例
Nov 17 #Javascript
JavaScript中定时控制Throttle、Debounce和Immediate详解
Nov 17 #Javascript
JS动态的把左边列表添加到右边的实现代码(可上下移动)
Nov 17 #Javascript
leaflet的开发入门教程
Nov 17 #Javascript
JavaScript中关于iframe滚动条的去除和保留
Nov 17 #Javascript
JS实现倒计时(天数、时、分、秒)
Nov 16 #Javascript
You might like
PHP初学者头疼问题总结
2006/10/09 PHP
在服务端进行目录建立、删除,文件上传、删除的过程的php代码
2008/09/10 PHP
php中计算程序运行时间的类代码
2012/11/03 PHP
PHP中func_get_args(),func_get_arg(),func_num_args()的区别
2013/09/30 PHP
JavaScript Array扩展实现代码
2009/10/14 Javascript
jQuery删除节点的三个方法即remove()detach()和empty()
2013/12/27 Javascript
可插入图片的TEXT文本框
2013/12/27 Javascript
js/jQuery简单实现选项卡功能
2014/01/02 Javascript
Eclipse下jQuery文件报错出现错误提示红叉
2014/01/13 Javascript
最佳的JavaScript错误处理实践
2016/07/16 Javascript
AngularJS 中文API参考手册
2016/07/28 Javascript
微信小程序 input输入框详解及简单实例
2017/01/10 Javascript
js实现模糊匹配功能
2017/02/15 Javascript
微信小程序 实现动态显示和隐藏某个控件
2017/04/27 Javascript
Angular中的interceptors拦截器
2017/06/25 Javascript
学习Vue组件实例
2018/04/28 Javascript
深入浅析Vue.js计算属性和侦听器
2018/05/05 Javascript
vue+element UI实现树形表格带复选框的示例代码
2019/04/16 Javascript
基于JavaScript的数据结构队列动画实现示例解析
2020/08/06 Javascript
[55:42]VG vs VGJ.T 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
讲解Python中的递归函数
2015/04/27 Python
详谈python3 numpy-loadtxt的编码问题
2018/04/29 Python
详解Python 协程的详细用法使用和例子
2018/06/15 Python
python用match()函数爬数据方法详解
2019/07/23 Python
Python 使用threading+Queue实现线程池示例
2019/12/21 Python
深入理解Python 多线程
2020/06/16 Python
如何用python批量调整视频声音
2020/12/22 Python
RUIFIER官网:英国奢侈高级珠宝品牌
2020/06/12 全球购物
策划助理岗位职责
2013/11/18 职场文书
劳动之星获奖感言
2014/02/01 职场文书
七年级政治教学反思
2014/02/03 职场文书
对教师的评语
2014/04/28 职场文书
语文复习计划
2015/01/19 职场文书
新郎父母婚礼答谢词
2015/09/29 职场文书
叶县这家生产军用电台的兵工厂,人称“四机部”,走出一上将
2022/02/18 无线电
InterProcessMutex实现zookeeper分布式锁原理
2022/03/21 Java/Android