用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提示 "object expected"的解决方法
Dec 13 Javascript
兼容IE和FF的js脚本代码小结(比较常用)
Dec 06 Javascript
Jquery下attr和removeAttr的使用方法
Dec 28 Javascript
使用jQuery快速解决input中placeholder值在ie中无法支持的问题
Jan 02 Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
Aug 13 Javascript
轻松学习Javascript闭包
Mar 01 Javascript
bootstrap插件treeview实现全选父节点下所有子节点和反选功能
Jul 21 Javascript
Vue+Element使用富文本编辑器的示例代码
Aug 14 Javascript
Vue中定义全局变量与常量的各种方式详解
Aug 23 Javascript
webpack多入口文件页面打包配置详解
Jan 09 Javascript
angular4 JavaScript内存溢出问题
Mar 06 Javascript
详解vue 2.6 中 slot 的新用法
Jul 09 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中突破基于HTTP_REFERER的防盗链措施(stream_context_create)
2011/03/29 PHP
浅谈PHP中其他类型转化为Bool类型
2016/03/28 PHP
yii2中结合gridview如何使用modal弹窗实例代码详解
2016/06/12 PHP
tp框架(thinkPHP)实现三次登陆密码错误之后锁定账号功能示例
2018/05/24 PHP
PHP利用百度ai实现文本和图片审核
2019/05/08 PHP
运用jquery实现table单双行不同显示并能单行选中
2009/07/25 Javascript
JQuery 获取和设置Select选项的代码
2010/02/07 Javascript
javascript中有趣的反柯里化深入分析
2012/12/05 Javascript
jquery mobile页面跳转后样式丢失js失效的解决方法
2014/09/06 Javascript
基于javascript实现单选及多选的向右和向左移动实例
2015/07/25 Javascript
jQuery增加与删除table列的方法
2016/03/01 Javascript
JavaScript中setTimeout和setInterval函数的传参及调用
2016/03/11 Javascript
基于javascript实现九九乘法表
2016/03/27 Javascript
关于JavaScript和jQuery的类型判断详解
2016/10/08 Javascript
纯原生js实现table表格的增删
2017/01/05 Javascript
BootStrap表单控件之复选框checkbox和单选择按钮radio
2017/05/23 Javascript
vue中倒计时组件的实例代码
2018/07/06 Javascript
解决vue2.0 element-ui中el-upload的before-upload方法返回false时submit()不生效问题
2018/08/24 Javascript
Node.js系列之发起get/post请求(2)
2019/08/30 Javascript
通过原生vue添加滚动加载更多功能
2019/11/21 Javascript
Javascript模块化机制实现原理详解
2020/04/02 Javascript
Element InfiniteScroll无限滚动的具体使用方法
2020/07/27 Javascript
基于JS实现操作成功之后自动跳转页面
2020/09/25 Javascript
Python多线程编程(一):threading模块综述
2015/04/05 Python
python集合用法实例分析
2015/05/30 Python
python dict 字典 以及 赋值 引用的一些实例(详解)
2017/01/20 Python
Python绑定方法与非绑定方法详解
2017/08/18 Python
python文件和文件夹复制函数
2020/02/07 Python
Python用dilb提取照片上人脸的示例
2020/10/26 Python
利用pipenv和pyenv管理多个相互独立的Python虚拟开发环境
2020/11/01 Python
html5时钟实现代码
2010/10/22 HTML / CSS
Bodum官网:咖啡和茶壶、玻璃器皿、厨房电器等
2018/08/01 全球购物
大学生职业规划书的范本
2014/02/18 职场文书
党的群众路线教育实践活动批评与自我批评范文
2014/10/16 职场文书
工程合作意向书范本
2015/05/09 职场文书
2015国庆节66周年标语
2015/07/30 职场文书