用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 相关文章推荐
检测是否已安装 .NET Framework 3.5的js脚本
Feb 14 Javascript
javascript 子窗体父窗体相互传值方法
May 31 Javascript
js中匿名函数的N种写法
Sep 08 Javascript
原来Jquery.load的方法可以一直load下去
Mar 28 Javascript
Google 爬虫如何抓取 JavaScript 的内容
Apr 07 Javascript
vue环境搭建简单教程
Nov 07 Javascript
Bootstarp在pycharm中的安装及简单的使用方法
Apr 19 Javascript
Vue基于vuex、axios拦截器实现loading效果及axios的安装配置
Apr 26 Javascript
详解Node.js异步处理的各种写法
Jun 09 Javascript
浅谈JS中this在各个场景下的指向
Aug 14 Javascript
JavaScript实现图片放大预览效果
Nov 02 Javascript
利用JS判断元素是否为数组的方法示例
Jan 08 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实现指定字符串中查找子字符串的方法
2015/03/17 PHP
extjs DataReader、JsonReader、XmlReader的构造方法
2009/11/07 Javascript
JS 控件事件小结
2012/10/31 Javascript
JavaScript改变HTML元素的样式改变CSS及元素属性
2013/11/12 Javascript
js使用eval解析json(js中使用json)
2014/01/17 Javascript
laytpl 精致巧妙的JavaScript模板引擎
2014/08/29 Javascript
NodeJS学习笔记之Connect中间件模块(二)
2015/01/27 NodeJs
JS网页在线获取鼠标坐标值的方法
2015/02/28 Javascript
JQuery实现超链接鼠标提示效果的方法
2015/06/10 Javascript
jQuery基于ajax实现带动画效果无刷新柱状图投票代码
2015/08/10 Javascript
jQuery自定义滚动条完整实例
2016/01/08 Javascript
微信开发 微信授权详解
2016/10/21 Javascript
基于vue.js轮播组件vue-awesome-swiper实现轮播图
2017/03/17 Javascript
vue-resource调用promise取数据方式详解
2017/07/21 Javascript
带你了解session和cookie作用原理区别和用法
2017/08/14 Javascript
javascript中数组的常用算法深入分析
2019/03/12 Javascript
Node.js 路由的实现方法
2019/06/05 Javascript
nodejs实现UDP组播示例方法
2019/11/04 NodeJs
vue3.0中使用postcss-pxtorem的具体方法
2019/11/20 Javascript
详解jQuery中的prop()使用方法
2020/01/05 jQuery
在vue中封装的弹窗组件使用队列模式实现方法
2020/07/23 Javascript
[03:57]DOTA2英雄梦之声_第03期_幻影刺客
2014/06/21 DOTA
python 文件与目录操作
2008/12/24 Python
Python文件处理
2016/02/29 Python
浅析Python的web.py框架中url的设定方法
2016/07/11 Python
Python打印输出数组中全部元素
2018/03/13 Python
基于canvas使用贝塞尔曲线平滑拟合折线段的方法
2018/01/10 HTML / CSS
西班牙英格列斯百货官网:El Corte Inglés
2016/09/25 全球购物
Revolution Beauty美国官网:英国知名化妆品网站
2018/07/23 全球购物
出资证明书范本(标准版)
2014/09/24 职场文书
求职简历自我评价2015
2015/03/10 职场文书
浅谈Python类的单继承相关知识
2021/05/12 Python
Python 循环读取数据内存不足的解决方案
2021/05/25 Python
JavaScript实例 ODO List分析
2022/01/22 Javascript
Windows server 2012 R2 安装IIS服务器
2022/04/29 Servers