用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 引起的安全问题
Dec 27 Javascript
js动态创建标签示例代码
Jun 09 Javascript
jquery实现两边飘浮可关闭的对联广告
Nov 27 Javascript
图文详解Javascript中的上下文和作用域
Feb 15 Javascript
Ajax验证用户名或昵称是否已被注册
Apr 05 Javascript
JavaScript 获取元素在父节点中的下标(推荐)
Jun 28 Javascript
JavaScript实现瀑布流图片效果
Jun 30 Javascript
微信小程序左滑动显示菜单功能的实现
Jun 14 Javascript
jQuery实现动画、消失、显现、渐出、渐入效果示例
Sep 06 jQuery
vue 集成jTopo 处理方法
Aug 07 Javascript
使用xampp将angular项目运行在web服务器的教程
Sep 16 Javascript
javaScript 实现重复输出给定的字符串的常用方法小结
Feb 20 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将字符串随机分割成不同长度数组的方法
2015/06/01 PHP
Jquery cookie操作代码
2010/03/14 Javascript
基于jquery实现的鼠标滑过按钮改变背景图片
2011/07/15 Javascript
JAVASCRIPT函数作用域和提前声明 分享
2013/08/22 Javascript
使用jquery菜单插件HoverTree仿京东无限级菜单
2014/12/18 Javascript
JS实现文字向下滚动完整实例
2015/02/06 Javascript
Jquery中使用show()与hide()方法动画显示和隐藏图片
2015/10/08 Javascript
javascript类型系统 Array对象学习笔记
2016/01/09 Javascript
浅谈jQuery 中的事件冒泡和阻止默认行为
2016/05/28 Javascript
echarts3 使用总结(绘制各种图表,地图)
2017/01/05 Javascript
NodeJs测试框架Mocha的安装与使用
2017/03/28 NodeJs
VUE引入第三方js包及调用方法讲解
2019/03/01 Javascript
解决layer.open后laydate失效的问题
2019/09/06 Javascript
在博客园博文中添加自定义右键菜单的方法详解
2020/02/05 Javascript
微信小程序实现选择地址省市区三级联动
2020/06/21 Javascript
python使用beautifulsoup从爱奇艺网抓取视频播放
2014/01/23 Python
python基于xml parse实现解析cdatasection数据
2014/09/30 Python
Python实现购物车功能的方法分析
2017/11/10 Python
Python用csv写入文件_消除空余行的方法
2018/07/06 Python
python画一个玫瑰和一个爱心
2020/08/18 Python
Python 实现Windows开机运行某软件的方法
2018/10/14 Python
解决pycharm回车之后不能换行或不能缩进的问题
2019/01/16 Python
python使用Paramiko模块实现远程文件拷贝
2019/04/30 Python
利用Python实现某OA系统的自动定位功能
2020/05/27 Python
Python lambda表达式原理及用法解析
2020/08/18 Python
Python爬取豆瓣数据实现过程解析
2020/10/27 Python
荟萃全球保健品:维他购
2018/05/09 全球购物
JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?
2015/10/22 面试题
网络编辑岗位职责范本
2014/02/10 职场文书
医药公司采购员岗位职责
2015/04/03 职场文书
新学期开学标语2015
2015/07/16 职场文书
2015国庆节放假通知范文
2015/07/30 职场文书
党员干部学习十八届五中全会精神心得体会
2016/01/05 职场文书
MySQL不使用order by实现排名的三种思路总结
2021/06/02 MySQL
MySQL限制查询和数据排序介绍
2022/03/25 MySQL
尝试使用Python爬取城市租房信息
2022/04/12 Python