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 相关文章推荐
IE7提供XMLHttpRequest对象为兼容
Mar 08 Javascript
JavaScript 继承的实现
Jul 09 Javascript
JQuery Ajax通过Handler访问外部XML数据的代码
Jun 01 Javascript
jquery图片倾斜层叠切换特效代码分享
Aug 27 Javascript
JS实现的左侧竖向滑动菜单效果代码
Oct 19 Javascript
Vue中render方法的使用详解
Jan 26 Javascript
Vue 中使用vue2-highcharts实现top功能的示例
Mar 05 Javascript
vue.js实现标签页切换效果
Jun 07 Javascript
vue中的watch监听数据变化及watch中各属性的详解
Sep 11 Javascript
Vue代码整洁之去重方法整理
Aug 06 Javascript
layui 富文本编辑器和textarea值的相互传递方法
Sep 18 Javascript
js实现前端界面导航栏下拉列表
Aug 27 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 连接mysql连接被重置的解决方法
2011/02/15 PHP
PHP对象相关知识总结
2017/04/09 PHP
javascript String 的扩展方法集合
2008/06/01 Javascript
new Date()问题在ie8下面的处理方法
2014/07/31 Javascript
Javascript验证用户输入URL地址是否为空及格式是否正确
2014/10/09 Javascript
如何用js实现鼠标向上滚动时浮动导航
2016/07/18 Javascript
easyui tree带checkbox实现单选的简单实例
2016/11/07 Javascript
使用Browserify来实现CommonJS的浏览器加载方法
2017/05/14 Javascript
分享19个JavaScript 有用的简写写法
2017/07/07 Javascript
JS实现带导航城市列表以及输入搜索功能
2018/01/04 Javascript
解决vue 打包发布去#和页面空白的问题
2018/09/04 Javascript
vue通过video.js解决m3u8视频播放格式的方法
2019/07/30 Javascript
JavaScript RegExp 对象用法详解
2019/09/24 Javascript
在vue中获取wangeditor的html和text的操作
2020/10/23 Javascript
解决vue项目中遇到 Cannot find module ‘chalk‘ 报错的问题
2020/11/05 Javascript
python使用内存zipfile对象在内存中打包文件示例
2014/04/30 Python
python之pandas用法大全
2018/03/13 Python
python 字典中文key处理,读取,比较方法
2018/07/06 Python
python模块导入的方法
2019/10/24 Python
使用python实现男神女神颜值打分系统(推荐)
2019/10/31 Python
使用pyshp包进行shapefile文件修改的例子
2019/12/06 Python
Python3变量与基本数据类型用法实例分析
2020/02/14 Python
IE9下html5初试小刀
2010/09/21 HTML / CSS
SmartBuyGlasses中国:唯视良品(销售名牌太阳镜、墨镜和眼镜框)
2017/07/03 全球购物
Shopping happy life西班牙:以最优惠的价格提供最好的时尚配饰
2020/03/13 全球购物
你所在的项目是如何确定版本号的
2015/12/28 面试题
护士自荐信
2013/10/25 职场文书
日语专业毕业生自荐信
2013/11/11 职场文书
法律专业推荐信范文
2013/11/29 职场文书
幼儿园小班家长寄语
2014/04/02 职场文书
劳动保障个人工作总结
2015/03/04 职场文书
2019财务管理制度最新范本!
2019/07/09 职场文书
话题作文之生命的旋律
2019/12/17 职场文书
2019年圣诞节祝福语集锦
2019/12/25 职场文书
Java中常用解析工具jackson及fastjson的使用
2021/06/28 Java/Android
Python NumPy灰度图像的压缩原理讲解
2021/08/04 Python