用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 相关文章推荐
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(上:事件篇)
Mar 24 Javascript
js 实现菜单上下显示附效果图
Nov 21 Javascript
jquery获取tr并更改tr内容示例代码
Feb 13 Javascript
jQuery中Ajax的get、post等方法详解
Jan 20 Javascript
JavaScript中document.forms[0]与getElementByName区别
Jan 21 Javascript
js实现在网页上简单显示时间的方法
Mar 02 Javascript
jQuery+php实时获取及响应文本框输入内容的方法
May 24 Javascript
SWFUpload多文件上传及文件个数限制的方法
May 31 Javascript
完美实现js焦点轮播效果(一)
Mar 07 Javascript
three.js实现3D模型展示的示例代码
Dec 31 Javascript
Vue 中的受控与非受控组件的实现
Dec 17 Javascript
JS实现页面鼠标点击出现图片特效
Aug 19 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生成静态文件的多种方法分享
2012/07/17 PHP
Win下如何安装PHP的APC拓展
2013/08/07 PHP
php实现通用的信用卡验证类
2015/03/24 PHP
smarty模板引擎之内建函数用法
2015/03/30 PHP
PHP也能干大事之PHP中的编码解码详解
2015/04/20 PHP
Javascript的一种模块模式
2008/03/22 Javascript
IE7中javascript操作CheckBox的checked=true不打勾的解决方法
2009/12/07 Javascript
基于jQuery的模仿新浪微博时间的组件
2011/10/04 Javascript
了解jQuery技巧来提高你的代码(个人觉得那个jquery的手册很不错)
2012/02/10 Javascript
javascript 星级评分效果(手写)
2012/12/24 Javascript
javascript表单验证和Window详解
2014/12/11 Javascript
提交按钮的name='submit'引起的js失效问题及原因
2015/02/25 Javascript
php结合imgareaselect实现图片裁剪
2015/07/05 Javascript
javascript实现日期时间动态显示示例代码
2015/09/08 Javascript
Javascript计算二维数组重复值示例代码
2016/12/18 Javascript
javascript 判断当前浏览器版本并判断ie版本
2017/02/17 Javascript
Vue通过input筛选数据
2020/10/26 Javascript
用纯Node.JS弹出Windows系统消息提示框实例(MessageBox)
2017/05/17 Javascript
react native实现往服务器上传网络图片的实例
2017/08/07 Javascript
解决Vue使用mint-ui loadmore实现上拉加载与下拉刷新出现一个页面使用多个上拉加载后冲突问题
2017/11/07 Javascript
在Vue中实现随hash改变响应菜单高亮
2020/03/09 Javascript
react PropTypes校验传递的值操作示例
2020/04/28 Javascript
vue中watch的用法汇总
2020/12/28 Vue.js
实例解析Python设计模式编程之桥接模式的运用
2016/03/02 Python
使用python socket分发大文件的实现方法
2019/07/08 Python
python 并发编程 非阻塞IO模型原理解析
2019/08/20 Python
tensorflow 实现从checkpoint中获取graph信息
2020/02/10 Python
python 解决tqdm模块不能单行显示的问题
2020/02/19 Python
python GUI库图形界面开发之PyQt5信号与槽的高级使用技巧(自定义信号与槽)详解与实例
2020/03/06 Python
Python通过socketserver处理多个链接
2020/03/18 Python
css3 矩阵的使用详解
2018/03/20 HTML / CSS
Canvas系列之滤镜效果
2019/02/12 HTML / CSS
西安事变观后感
2015/06/12 职场文书
员工安全责任协议书
2016/03/22 职场文书
导游词之蓬莱长岛
2019/12/17 职场文书
python将图片转为矢量图的方法步骤
2021/03/30 Python