用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 相关文章推荐
JQuery实现倒计时按钮的实现代码
Mar 23 Javascript
几种延迟加载JS代码的方法加快网页的访问速度
Oct 12 Javascript
JS关闭窗口或JS关闭页面的几种代码分享
Oct 25 Javascript
javascript去掉前后空格的实例
Nov 07 Javascript
使用Chrome调试JavaScript的断点设置和调试技巧
Dec 16 Javascript
jQuery菜单插件superfish使用指南
Apr 21 Javascript
深入浅析Node.js 事件循环
Dec 20 Javascript
详解JS正则replace的使用方法
Mar 06 Javascript
javascript 中iframe高度自适应(同域)实例详解
May 16 Javascript
深入浅析Vue全局组件与局部组件的区别
Jun 15 Javascript
javascript写一个ajax自动拦截并下载数据代码实例
Sep 07 Javascript
简单了解JavaScript作用域
Jul 31 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判断输入不超过mysql的varchar字段的长度范围
2011/06/24 PHP
创建公共调用 jQuery Ajax 带返回值
2012/08/01 Javascript
简单的jquery左侧导航栏和页面选中效果
2014/08/21 Javascript
使用FlexiGrid实现Extjs表格效果方法分享
2014/12/16 Javascript
详解AngularJS的通信机制
2015/06/18 Javascript
简单谈谈javascript中的变量、作用域和内存问题
2015/08/30 Javascript
js密码强度校验
2015/11/10 Javascript
jquery实现表格隔行换色效果
2015/11/19 Javascript
location.hash保存页面状态的技巧
2016/04/28 Javascript
jQuery多级联动下拉插件chained用法示例
2016/08/20 Javascript
javascript 显示全局变量与隐式全局变量的区别
2017/02/09 Javascript
在小程序中使用canvas的方法示例
2018/09/17 Javascript
vue实现将一个数组内的相同数据进行合并
2019/11/07 Javascript
基于element-ui对话框el-dialog初始化的校验问题解决
2020/09/11 Javascript
JavaScript 绘制饼图的示例
2021/02/19 Javascript
使用python获取csv文本的某行或某列数据的实例
2018/04/03 Python
python 不以科学计数法输出的方法
2018/07/16 Python
python自动化测试之DDT数据驱动的实现代码
2019/07/23 Python
Python-接口开发入门解析
2019/08/01 Python
详解Python中的正斜杠与反斜杠
2019/08/09 Python
Python基于jieba, wordcloud库生成中文词云
2020/05/13 Python
python 3.8.3 安装配置图文教程
2020/05/21 Python
python中slice参数过长的处理方法及实例
2020/12/15 Python
Python3爬虫ChromeDriver的安装实例
2021/02/06 Python
移动端html5判断是否滚动到底部并且下拉加载
2019/11/19 HTML / CSS
加拿大城市本地限时优惠:Buytopia.ca
2018/09/19 全球购物
Etam俄罗斯:法国女士内衣和家居服网上商店
2019/10/30 全球购物
一道输出判断型Java面试题
2014/10/01 面试题
幼儿园长自我鉴定
2013/10/17 职场文书
幼儿园中秋节活动方案
2014/02/06 职场文书
农村面貌改造提升实施方案
2014/03/18 职场文书
处级干部反四风个人对照检查材料思想汇报
2014/09/27 职场文书
公司股份转让协议书范本
2015/01/28 职场文书
人力资源部岗位职责
2015/02/11 职场文书
2019入党申请书格式
2019/06/25 职场文书