用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 相关文章推荐
推荐10个超棒的jQuery工具提示插件
Oct 11 Javascript
jQuery动画效果-slideUp slideDown上下滑动示例代码
Aug 28 Javascript
JS简单计算器实例
Jan 20 Javascript
jQuery及JS实现循环中暂停的方法
Feb 02 Javascript
纯js代码制作的网页时钟特效【附实例】
Mar 30 Javascript
React.js入门实例教程之创建hello world 的5种方式
May 11 Javascript
JS iFrame加载慢怎么解决
May 13 Javascript
JS实现的简单拖拽购物车功能示例【附源码下载】
Jan 03 Javascript
2019 年编写现代 JavaScript 代码的5个小技巧(小结)
Jan 15 Javascript
javascript如何实现create方法
Nov 04 Javascript
javascript实现超好看的3D烟花特效
Jan 01 Javascript
使用Vue实现简单计算器
Feb 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中遍历stdclass object的实现代码
2011/06/09 PHP
关于PHP二进制流 逐bit的低位在前算法(详解)
2013/06/13 PHP
通过修改Laravel Auth使用salt和password进行认证用户详解
2017/08/17 PHP
Ajax::prototype 源码解读
2007/01/22 Javascript
JavaScript 基础篇(一)
2012/03/30 Javascript
EasyUI,点击开启编辑框,并且编辑框获得焦点的方法
2015/03/01 Javascript
js实现鼠标经过表格行变色的方法
2015/05/12 Javascript
第五篇Bootstrap 排版
2016/06/21 Javascript
AngularJS  $modal弹出框实例代码
2016/08/24 Javascript
JS添加或修改控件的样式(Class)实现方法
2016/10/15 Javascript
jQuery实现获取隐藏div高度的方法示例
2017/02/09 Javascript
详解node服务器中打开html文件的两种方法
2017/09/18 Javascript
React Native 截屏组件的示例代码
2017/12/06 Javascript
微信小程序使用npm支持踩坑
2018/11/07 Javascript
Nodejs环境实现socket通信过程解析
2020/07/03 NodeJs
基于JavaScript实现轮播图效果
2021/01/02 Javascript
python文件操作之目录遍历实例分析
2015/05/20 Python
Python reduce()函数的用法小结
2017/11/15 Python
解决python中 f.write写入中文出错的问题
2018/10/31 Python
浅谈python 中类属性共享的问题
2019/07/02 Python
详解python中的index函数用法
2019/08/06 Python
解决Python3下map函数的显示问题
2019/12/04 Python
Anaconda和ipython环境适配的实现
2020/04/22 Python
python 在sql语句中使用%s,%d,%f说明
2020/06/06 Python
Win10下配置tensorflow-gpu的详细教程(无VS2015/2017)
2020/07/14 Python
美国汽车零部件和配件网站:CarParts
2019/03/13 全球购物
Unix如何在一行中运行多个命令
2015/05/29 面试题
体育馆的标语
2014/06/24 职场文书
初中家长评语和期望
2014/12/26 职场文书
刑事附带民事起诉状
2015/05/19 职场文书
2015年度学校应急管理工作总结
2015/10/22 职场文书
2019年朋友圈经典励志语录50条
2019/07/05 职场文书
年终奖金发放管理制度,中小企业适用,拿去救急吧!
2019/07/12 职场文书
不知如何爱孩子,这些方法教会您
2019/08/06 职场文书
节约用水广告语60条
2019/11/14 职场文书
Java tomcat手动配置servlet详解
2021/11/27 Java/Android