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 相关文章推荐
jQuery实现id模糊查询的小例子
Mar 19 Javascript
Json序列化和反序列化方法解析
Dec 19 Javascript
js获取当前页面的url网址信息
Jun 12 Javascript
javascript常用的方法整理
Aug 20 Javascript
js右下角弹出提示框示例代码
Jan 12 Javascript
Bootstrap每天必学之模态框(Modal)插件
Apr 26 Javascript
jquery的ajax提交form表单的两种方法小结(推荐)
May 25 Javascript
JavaScript调试的多个必备小Tips
Jan 15 Javascript
react-router4按需加载(踩坑填坑)
Jan 06 Javascript
JavaScript中的惰性载入函数及优势
Feb 18 Javascript
AutoJs实现刷宝短视频的思路详解
May 22 Javascript
微信小程序实现modal弹出框遮罩层组件(可带文本框)
Dec 20 Javascript
详解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
获取远程文件大小的php函数
2010/01/11 PHP
PHP中比较时间大小实例
2014/08/21 PHP
使用jQuery模板来展现json数据的代码
2010/10/22 Javascript
jQuery EasyUI API 中文文档 - NumberBox数字框
2011/10/13 Javascript
js Math 对象的方法
2013/09/01 Javascript
jQuery实现鼠标可拖动调整表格列宽度
2014/05/26 Javascript
利用jQuery设计一个简单的web音乐播放器的实例分享
2016/03/08 Javascript
JavaScript String 对象常用方法总结
2016/04/28 Javascript
浅谈js中对象的使用
2016/08/11 Javascript
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
2016/12/15 Javascript
详解vue跨组件通信的几种方法
2017/06/15 Javascript
AngularJS select设置默认值的实现方法
2017/08/25 Javascript
vue 实现类似淘宝星级评分的示例
2018/03/01 Javascript
Angular路由ui-router配置详解
2018/08/01 Javascript
Python基于tkinter模块实现的改名小工具示例
2017/07/27 Python
机器学习之KNN算法原理及Python实现方法详解
2018/07/09 Python
python覆盖写入,追加写入的实例
2019/06/26 Python
PyTorch中的Variable变量详解
2020/01/07 Python
用Python绘制漫步图实例讲解
2020/02/26 Python
python中线程和进程有何区别
2020/06/17 Python
python基于openpyxl生成excel文件
2020/12/23 Python
Django使用django-simple-captcha做验证码的实现示例
2021/01/07 Python
HTML5+CSS3绘制锯齿状的矩形
2016/03/01 HTML / CSS
AP澳洲中文网:澳洲正品直邮,包税收件无忧
2019/07/12 全球购物
aden + anais英国官网:美国婴儿贴身用品品牌
2019/09/08 全球购物
澳大利亚买卖正宗二手奢侈品交易平台:Luxe.It.Fwd
2019/10/16 全球购物
战友聚会邀请函
2014/01/18 职场文书
大学生个人自荐信样本
2014/03/02 职场文书
讲解员培训方案
2014/05/04 职场文书
党员承诺践诺书
2014/05/20 职场文书
大二学生学年自我鉴定
2014/09/12 职场文书
出租房屋协议书
2014/09/14 职场文书
群众路线教育实践活动批评与自我批评
2014/09/15 职场文书
单位工作证明书格式
2014/10/04 职场文书
九九重阳节标语
2014/10/07 职场文书
乔迁新居祝福语
2019/11/04 职场文书