用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 相关文章推荐
js、css、img等浏览器缓存问题的2种解决方案
Oct 23 Javascript
Bootstrap每天必学之简单入门
Nov 19 Javascript
JavaScript+html5 canvas绘制的小人效果
Jan 27 Javascript
JS导出PDF插件的方法(支持中文、图片使用路径)
Jul 12 Javascript
微信小程序使用第三方库Underscore.js步骤详解
Sep 27 Javascript
JavaScript中捕获与冒泡详解及实例
Feb 03 Javascript
jQuery插件开发发送短信倒计时功能代码
May 09 jQuery
Vue2.x中的Render函数详解
May 30 Javascript
详解Vue2.0里过滤器容易踩到的坑
Jun 01 Javascript
vue.js中引入vuex储存接口数据及调用的详细流程
Dec 14 Javascript
JS中原始值和引用值的储存方式示例详解
Mar 23 Javascript
openlayers实现地图弹窗
Sep 25 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&java(二)
2006/10/09 PHP
PHP中的日期处理方法集锦
2007/01/02 PHP
PHP之sprintf函数用法详解
2014/11/12 PHP
PHP里8个鲜为人知的安全函数分析
2014/12/09 PHP
制作个性化的WordPress登陆界面的实例教程
2016/05/21 PHP
Laravel框架分页实现方法分析
2018/06/12 PHP
PHP操作redis实现的分页列表,新增,删除功能封装类与用法示例
2018/08/04 PHP
解决 FireFox 下[使用event很麻烦] 的问题.
2006/08/22 Javascript
js图片跟随鼠标移动代码
2015/11/26 Javascript
学习使用bootstrap3栅格系统
2016/04/12 Javascript
JavaScript 轮播图和自定义滚动条配合鼠标滚轮分享代码贴
2016/10/28 Javascript
vue中用H5实现文件上传的方法实例代码
2017/05/27 Javascript
浅析JS抽象工厂模式
2017/12/14 Javascript
Vue项目添加动态浏览器头部title的方法
2018/07/11 Javascript
nodejs二进制与Buffer的介绍与使用
2019/07/11 NodeJs
微信小程序中的列表切换功能实例代码详解
2020/06/09 Javascript
[01:23:45]DOTA2-DPC中国联赛 正赛 CDEC vs Dragon BO3 第一场 1月22日
2021/03/11 DOTA
python基于multiprocessing的多进程创建方法
2015/06/04 Python
Python编程实现输入某年某月某日计算出这一天是该年第几天的方法
2017/04/18 Python
python3设计模式之简单工厂模式
2017/10/17 Python
python socket网络编程之粘包问题详解
2018/04/28 Python
Pandas 合并多个Dataframe(merge,concat)的方法
2018/06/08 Python
python实现全盘扫描搜索功能的方法
2019/02/14 Python
Pycharm debug调试时带参数过程解析
2020/02/03 Python
tensorflow自定义激活函数实例
2020/02/04 Python
关于python中remove的一些坑小结
2021/01/04 Python
Clarks鞋澳大利亚官方网站:Clarks Australia
2019/12/25 全球购物
请写出 BOOL flag 与"零值"比较的 if 语句
2016/02/29 面试题
自主招生自荐信范文
2013/12/04 职场文书
2014年小班元旦活动方案
2014/02/16 职场文书
中式结婚主持词
2014/03/14 职场文书
还款承诺书范本
2015/01/20 职场文书
调解书格式范本
2015/05/20 职场文书
法定代表人身份证明书
2015/06/18 职场文书
网络营销实训总结
2015/08/03 职场文书
2016三八妇女节慰问信
2015/11/30 职场文书