用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 相关文章推荐
在IE模态窗口中自由查看HTML源码的方法
Mar 08 Javascript
javascript重写alert方法的实例代码
Mar 29 Javascript
关于删除时的提示处理(确定删除吗)
Nov 03 Javascript
Javascript学习笔记之 对象篇(四) : for in 循环
Jun 24 Javascript
Visual Studio中js调试的方法图解
Jun 30 Javascript
jQuery表格列宽可拖拽改变且兼容firfox
Sep 03 Javascript
jQuery DOM插入节点操作指南
Mar 03 Javascript
jQuery实现自定义右键菜单的树状菜单效果
Sep 02 Javascript
JavaScript简单实现弹出拖拽窗口(二)
Jun 17 Javascript
JavaScript实现相册弹窗功能(zepto.js)
Jun 21 Javascript
JS给swf传参数的实现方法
Sep 13 Javascript
JavaScript oncopy事件用法实例解析
May 13 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 ZipArchive压缩函数详解实例
2013/11/06 PHP
laravel学习教程之关联模型
2016/07/30 PHP
PHP通过CURL实现定时任务的图片抓取功能示例
2016/10/03 PHP
php性能分析之php-fpm慢执行日志slow log用法浅析
2016/10/17 PHP
学习YUI.Ext 第六天--关于树TreePanel(Part 1)
2007/03/10 Javascript
关于事件mouseover ,mouseout ,mouseenter,mouseleave的区别
2015/10/12 Javascript
Jquery实现的简单轮播效果【附实例】
2016/04/19 Javascript
javascript常见数字进制转换实例分析
2016/04/21 Javascript
深入理解MVC中的时间js格式化
2016/05/19 Javascript
JavaScript代码里的判断小结
2016/08/22 Javascript
如何学JavaScript?前辈的经验之谈
2016/12/28 Javascript
Bootstrap实现的表格合并单元格示例
2018/02/06 Javascript
layui use 定义js外部引用函数的方法
2019/09/26 Javascript
基于原生js实现九宫格算法代码实例
2020/07/03 Javascript
js实现全选和全不选功能
2020/07/28 Javascript
[01:19:11]Ti4 循环赛第二日 NaVi.us vs iG
2014/07/11 DOTA
easy_install python包安装管理工具介绍
2013/02/10 Python
python逐行读取文件内容的三种方法
2014/01/20 Python
在Python的Flask框架中使用日期和时间的教程
2015/04/21 Python
Python 调用Java实例详解
2017/06/02 Python
Python中xrange与yield的用法实例分析
2017/12/26 Python
python3中eval函数用法使用简介
2019/08/02 Python
Django rstful登陆认证并检查session是否过期代码实例
2019/08/13 Python
python3中布局背景颜色代码分析
2020/12/01 Python
CSS3中Animation属性的使用详解
2015/08/06 HTML / CSS
Gtech官方网站:地毯清洁器、吸尘器及园艺设备
2018/05/23 全球购物
自荐信格式的六要素
2013/09/21 职场文书
材料成型专业个人求职信范文
2013/09/25 职场文书
水毁工程实施方案
2014/04/01 职场文书
大学共青团员个人自我评价
2014/04/16 职场文书
法人代表任命书范本
2014/06/05 职场文书
出差报告怎么写
2014/11/06 职场文书
综合实践活动报告
2015/02/05 职场文书
2015年度企业工作总结
2015/05/21 职场文书
SQL Server数据库基本概念、组成、常用对象与约束
2022/03/20 SQL Server
threejs太阳光与阴影效果实例代码
2022/04/05 Javascript