Vue.js 中的 $watch使用方法


Posted in Javascript onMay 25, 2017

这两天学习了Vue.js 中的 $watch这个地方知识点挺多的,而且很重要,所以,今天添加一点小笔记。

Vue.js 中的 $watch使用方法

github 源码 

Observer, Watcher, vm 可谓 Vue 中比较重要的部分,检测数据变动后视图更新的重要环节。下面我们来看看 如何实现一个简单的 $watch 功能,当然Vue 中使用了很多优化手段,在本文中暂不一一讨论。

例子:

// 创建 vm
let vm = new Vue({
 data: 'a'
})

// 键路径
vm.$watch('a.b.c', function () {
 // 做点什么
})

先阐明在这个 demo 以及Vue 中,它们的关系:

vm 调用 $watch 后,首先调用 observe 函数 创建 Observer 实例观察数据,Observer 又创建 Dep , Dep 用来维护订阅者。然后创建 Watcher 实例提供 update 函数。一旦数据变动,就层层执行回调函数。

Vue.js 中的 $watch使用方法

Observer和observe

递归调用 observe 函数创建 Observer。在创建 Observer 的过程中,使用 Object.defineProperty() 函数为其添加 get set 函数, 并创建 Dep 实例。

export function observe (val) {
 if (!val || typeof val !== 'object') {
  return
 }
 return new Observer(val)
}
function defineReactive (obj, key, val) {
 var dep = new Dep()

 var property = Object.getOwnPropertyDescriptor(obj, key)
 // 是否允许修改
 if (property && property.configurable === false) {
  return
 }

 // 获取定义好的 get set 函数
 var getter = property && property.get
 var setter = property && property.set

 var childOb = observe(val)
 Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: () => {
   var value = getter ? getter.call(obj) : val
   // 说明是 Watcher 初始化时获取的, 就添加订阅者
   if (Dep.target) {
    dep.depend()
    if (childOb) {
     childOb.dep.depend()
    }
    // if isArray do some....
   }
   return value
  },
  set: (newVal) => {
   var value = getter ? getter.call(obj) : val
   if (value === newVal) {
    return
   }
   if (setter) {
    setter.call(obj, newVal)
   } else {
    val = newVal
   }
   childOb = observe(newVal)
   dep.notify()
  }
 })
}

你可能会疑问 Dep.target 是个什么鬼??

答案是:Watcher, 我们接下来看

Dep

export default function Dep () {
 this.subs = []
}

// 就是你!!~
Dep.target = null 

// 添加订阅者
Dep.prototype.addSub = function (sub) {
 this.subs.push(sub)
}

// 添加依赖
Dep.prototype.depend = function () {
 Dep.target.addDep(this)
}

// 通知订阅者:要更新啦~
Dep.prototype.notify = function () {
 this.subs.forEach(sub => sub.update())
}

Watcher

为了给每个数据添加订阅者,我们想到的办法是在数据的 get 函数中, 但是 get 函数会调用很多次呀~。。。 肿么办?那就给 Dep 添加个参数 target

export default function Watcher (vm, expOrFn, cb) {
 this.cb = cb
 this.vm = vm
 this.expOrFn = expOrFn
 this.value = this.get()
}

Watcher.prototype.get = function () {
 Dep.target = this
 const value = this.vm._data[this.expOrFn]
 // 此时 target 有值,此时执行到了上面的 defineReactive 函数中 get 函数。就添加订阅者
 Dep.target = null
 // 为了不重复添加 就设置为 null
 return value
}

Vue Instance

在 Vue Instance 做得最多的事情就是初始化 State, 添加函数等等。

// Vue 实例
export default function Vue(options) {
 this.$options = options
 this._initState()
}

// 初始化State
Vue.prototype._initState = function () {
 let data = this._data = this.$options.data
 Object.keys(data).forEach(key => this._proxy(key))
 observe(data, this)
}

// $watch 函数,
Vue.prototype.$watch = function (expOrFn, fn, options) {
 new Watcher(this, expOrFn, fn)
}

总结

至此,我们已经实现了一个简单的 $watch 函数, Object.defineProperty() 函数可谓是举足轻重, 因此不支持该函数的浏览器, Vue 均不支持。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
用tip解决Ext列宽度不够的问题
Dec 13 Javascript
json对象转字符串如何实现
Dec 02 Javascript
JS Loading功能的简单实现
Nov 29 Javascript
JS和函数式语言的三特性
Mar 05 Javascript
JS调用某段SQL语句的方法
Oct 20 Javascript
canvas实现环形进度条效果
Mar 23 Javascript
vue-router 权限控制的示例代码
Sep 21 Javascript
mongoose设置unique不生效问题的解决及如何移除unique的限制
Nov 07 Javascript
详解webpack打包第三方类库的正确姿势
Oct 20 Javascript
vue 实现微信浮标效果
Sep 01 Javascript
jQuery实现的分页插件完整示例
May 26 jQuery
vue3+typeScript穿梭框的实现示例
Dec 29 Vue.js
详解Javascript获取缓存和清除缓存API
May 25 #Javascript
Angularjs 实现动态添加控件功能
May 25 #Javascript
JavaScript实现自动跳转文本功能
May 25 #Javascript
angularjs项目的页面跳转如何实现(5种方法)
May 25 #Javascript
AngularJS基于factory创建自定义服务的方法详解
May 25 #Javascript
AngularJS读取JSON及XML文件的方法示例
May 25 #Javascript
bootstrap+jQuery实现的动态进度条功能示例
May 25 #jQuery
You might like
实用函数8
2007/11/08 PHP
php并发加锁示例
2016/10/17 PHP
centos+php+coreseek+sphinx+mysql之一coreseek安装篇
2016/10/25 PHP
PHP结合jquery ajax实现上传多张图片,并限制图片大小操作示例
2019/03/01 PHP
使用laravel根据用户类型来显示或隐藏字段
2019/10/17 PHP
fireworks菜单生成器mm_menu.js在 IE 7.0 显示问题的解决方法
2009/10/20 Javascript
向左滚动文字 js代码效果
2013/08/17 Javascript
javascript中创建对象的几种方法总结
2013/11/01 Javascript
Javascript MVC框架Backbone.js详解
2014/09/18 Javascript
浅谈Javascript中匀速运动的停止条件
2014/12/19 Javascript
JS拖拽组件学习使用
2016/01/19 Javascript
vue实现移动端轻量日期组件不依赖第三方库的方法
2019/04/28 Javascript
简单了解Javscript中兄弟ifream的方法调用
2019/06/17 Javascript
Windows上node.js的多版本管理工具用法实例分析
2019/11/06 Javascript
完美解决vue 中多个echarts图表自适应的问题
2020/07/19 Javascript
详解Vue的mixin策略
2020/11/19 Vue.js
python在windows下实现ping操作并接收返回信息的方法
2015/03/20 Python
在Python中使用CasperJS获取JS渲染生成的HTML内容的教程
2015/04/09 Python
Python栈类实例分析
2015/06/15 Python
Python中的条件判断语句基础学习教程
2016/02/07 Python
浅析Git版本控制器使用
2017/12/10 Python
基于DATAFRAME中元素的读取与修改方法
2018/06/08 Python
windows上安装python3教程以及环境变量配置详解
2019/07/18 Python
如何基于python实现画不同品种的樱花树
2020/01/03 Python
jupyter修改文件名方式(TensorFlow)
2020/04/21 Python
Python利用命名空间解析XML文档
2020/08/10 Python
python 实现非极大值抑制算法(Non-maximum suppression, NMS)
2020/10/15 Python
python中绕过反爬虫的方法总结
2020/11/25 Python
css3的transition属性详解
2014/12/15 HTML / CSS
保密承诺书范文
2014/03/27 职场文书
建筑施工安全责任书
2014/07/24 职场文书
普通党员个人整改措施
2014/10/27 职场文书
计算机考试作弊检讨书1000字
2015/01/01 职场文书
考研英语复习计划
2015/01/19 职场文书
单位综合评价意见
2015/06/05 职场文书
物业保洁员管理制度
2015/08/05 职场文书