用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开源框架-jQuery使用手册(1)
Mar 10 Javascript
javascript基本包装类型介绍
Apr 10 Javascript
JavaScript严格模式详解
Nov 18 Javascript
又一款js时钟!transform实现时钟效果
Aug 15 Javascript
Vue.js 中的 $watch使用方法
May 25 Javascript
JavaScript之underscore_动力节点Java学院整理
Jul 03 Javascript
vue2.0 实现页面导航提示引导的方法
Mar 13 Javascript
Bootstrap table表格初始化表格数据的方法
Jul 25 Javascript
webpack的CSS加载器的使用
Sep 11 Javascript
微信小程序MUI导航栏透明渐变功能示例(通过改变rgba的a值实现)
Jan 24 Javascript
Node.js API详解之 V8模块用法实例分析
Jun 05 Javascript
jQuery实现移动端扭蛋机抽奖
Nov 08 jQuery
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常用函数的使用汇总
2013/06/08 PHP
php简单实现查询数据库返回json数据
2015/04/16 PHP
PHP实现动态web服务器方法
2015/07/29 PHP
浅谈socket同步和异步、阻塞和非阻塞、I/O模型
2016/12/15 PHP
javascript中将Object转换为String函数代码 (json str)
2012/04/29 Javascript
ajax处理php返回json数据的实例代码
2013/01/24 Javascript
Javascript浅谈之this
2013/12/17 Javascript
AngularJS轻松实现双击排序的功能
2016/08/30 Javascript
12 款 JS 代码测试必备工具(翻译)
2016/12/13 Javascript
详谈js中window.location.search的用法和作用
2017/02/13 Javascript
angular中ui calendar的一些使用心得(推荐)
2017/11/03 Javascript
React Native自定义控件底部抽屉菜单的示例
2018/02/08 Javascript
react中fetch之cors跨域请求的实现方法
2018/03/14 Javascript
使用async await 封装 axios的方法
2018/07/09 Javascript
如何在 JavaScript 中更好地利用数组
2018/09/27 Javascript
angular 服务的单例模式(依赖注入模式下)详解
2018/10/22 Javascript
Vuex 使用 v-model 配合 state的方法
2018/11/13 Javascript
angular 服务随记小结
2019/05/06 Javascript
Node.js使用MongoDB的ObjectId作为查询条件的方法
2019/09/10 Javascript
Vue 自定义指令功能完整实例
2019/09/17 Javascript
js实现3D旋转相册
2020/08/02 Javascript
[02:55]2018DOTA2国际邀请赛勇士令状不朽珍藏Ⅲ饰品一览
2018/08/01 DOTA
pycharm 使用心得(七)一些实用功能介绍
2014/06/06 Python
Python中标准库OS的常用方法总结大全
2017/07/19 Python
Python openpyxl 遍历所有sheet 查找特定字符串的方法
2018/12/10 Python
使用python绘制3维正态分布图的方法
2018/12/29 Python
nginx搭建基于python的web环境的实现步骤
2020/01/03 Python
matplotlib制作雷达图报错ValueError的实现
2021/01/05 Python
外贸英语专业求职信范文
2013/12/25 职场文书
网上快餐厅创业计划书
2014/02/01 职场文书
高校教师岗位职责
2014/03/18 职场文书
大队干部竞选演讲稿
2014/04/28 职场文书
小学班主任心得体会
2016/01/07 职场文书
2016大学生国家助学贷款承诺书
2016/03/25 职场文书
导游词之黄帝陵景区
2019/09/16 职场文书
第四次工业革命,打工人与机器人的竞争
2022/04/21 数码科技