用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 相关文章推荐
收集的网上用的ajax之chat.js文件
Apr 08 Javascript
JavaScript 申明函数的三种方法 每个函数就是一个对象(一)
Dec 04 Javascript
微博@符号的用户名提示效果。(想@到谁?)
Nov 05 Javascript
js事件冒泡实例分享(已测试)
Apr 23 Javascript
ECMAScript6函数剩余参数(Rest Parameters)
Jun 12 Javascript
ECMAScript6中Set/WeakSet详解
Jun 12 Javascript
jquery实现鼠标悬浮停止轮播特效
Aug 20 Javascript
webpack学习笔记之优化缓存、合并、懒加载
Aug 24 Javascript
对angularJs中ng-style动态改变样式的实例讲解
Sep 30 Javascript
Vue中 v-if/v-show/插值表达式导致闪现的原因及解决办法
Oct 12 Javascript
vue 关闭浏览器窗口的时候,清空localStorage的数据示例
Nov 06 Javascript
es6中Promise 对象基本功能与用法实例分析
Feb 23 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实现的遍历文件夹下所有文件,编辑删除
2010/01/05 PHP
php 获取本机外网/公网IP的代码
2010/05/09 PHP
需要注意的几个PHP漏洞小结
2012/02/05 PHP
php文件服务实现虚拟挂载其他目录示例
2014/04/17 PHP
PHP使用mysql_fetch_row查询获得数据行列表的方法
2015/03/18 PHP
php设计模式之装饰模式应用案例详解
2019/06/17 PHP
JavaScript的setAttribute兼容性问题解决方法
2013/11/11 Javascript
浅谈JavaScript的事件
2015/02/27 Javascript
JS使用oumousemove和oumouseout动态改变图片显示的方法
2015/03/31 Javascript
在JavaScript中处理数组之reverse()方法的使用
2015/06/09 Javascript
JavaScript实现的类字典插入或更新方法实例
2015/07/10 Javascript
JS模仿编辑器实时改变文本框宽度和高度大小的方法
2015/08/17 Javascript
AngularJS中的promise用法分析
2017/05/19 Javascript
bootstrap栅格系统示例代码分享
2017/05/22 Javascript
让Vue也可以使用Redux的方法
2018/05/23 Javascript
详解SPA中前端路由基本原理与实现方式
2018/09/12 Javascript
详解vuex commit保存数据技巧
2018/12/25 Javascript
JavaScript格式化json和xml的方法示例
2019/01/22 Javascript
jQuery实现checkbox全选、反选及删除等操作的方法详解
2019/08/02 jQuery
JS动态图片的实现方法完整示例
2020/01/13 Javascript
Vue移动端用淘宝弹性布局lib-flexible插件做适配的方法
2020/05/26 Javascript
js瀑布流布局的实现
2020/06/28 Javascript
使用js获取身份证年龄的示例代码
2020/12/11 Javascript
微信小程序弹窗禁止页面滚动的实现代码
2020/12/30 Javascript
Python设计模式编程中Adapter适配器模式的使用实例
2016/03/02 Python
Python-嵌套列表list的全面解析
2016/06/08 Python
Python加载带有注释的Json文件实例
2018/05/23 Python
python异步Web框架sanic的实现
2020/04/27 Python
Python Selenium XPath根据文本内容查找元素的方法
2020/12/07 Python
canvas与html5实现视频截图功能示例
2016/12/15 HTML / CSS
迷你分体式空调:SoGoodToBuy
2018/08/07 全球购物
医科大学生毕业的自我评价分享
2013/11/12 职场文书
应聘自荐信
2013/12/14 职场文书
供货协议书范本
2014/04/22 职场文书
公司更名通知函
2015/04/24 职场文书
python实现简单的名片管理系统
2021/04/26 Python