Vue.js 中的 $watch使用方法

 更新时间:2017年05月25日 16:58:08   作者:ericjj  
本篇文章中主要介绍了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 函数。一旦数据变动,就层层执行回调函数。


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 均不支持。

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

相关文章

  • Vue-cli3简单使用(图文步骤)

    Vue-cli3简单使用(图文步骤)

    这篇文章主要介绍了Vue-cli3简单使用(图文步骤),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-04-04
  • Vue实现6位数密码效果

    Vue实现6位数密码效果

    这篇文章主要为大家详细介绍了Vue实现6位数密码,优化iOS WebView卡顿,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • vue中如何简单封装axios浅析

    vue中如何简单封装axios浅析

    Axios 毋庸多说大家在前端开发中常用的一个发送 HTTP 请求的库,用过的都知道,篇文章主要给大家介绍了关于vue中如何简单封装axios的相关资料,需要的朋友可以参考下
    2021-06-06
  • nuxt框架中对vuex进行模块化设置的实现方法

    nuxt框架中对vuex进行模块化设置的实现方法

    这篇文章主要介绍了nuxt框架中对vuex进行模块化设置的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • vue动态添加store、路由和国际化配置方式

    vue动态添加store、路由和国际化配置方式

    这篇文章主要介绍了vue动态添加store、路由和国际化配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 利用Vue+intro.js实现页面新手引导流程功能

    利用Vue+intro.js实现页面新手引导流程功能

    在同学们使用某些网站的新版本页面的时候,经常会出现一个类似于新手引导一样的效果,来帮助同学们更好的熟悉新版本页面的功能和使用,这篇文章主要给大家介绍了关于如何利用Vue+intro.js实现页面新手引导流程功能的相关资料,需要的朋友可以参考下
    2023-11-11
  • Vue3 Props没有默认值但报错的解决方案

    Vue3 Props没有默认值但报错的解决方案

    这篇文章主要介绍了Vue3 Props没有默认值但报错的解决方案,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-04-04
  • 详解Vue项目中实现锚点定位

    详解Vue项目中实现锚点定位

    这篇文章主要介绍了Vue项目中实现锚点定位,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • VUE中V-IF条件判断改变元素的样式操作

    VUE中V-IF条件判断改变元素的样式操作

    这篇文章主要介绍了VUE中V-IF条件判断改变元素的样式操作,具有很好的参考价值,希望对大家有所帮助。一起跟随想过来看看吧
    2020-08-08
  • UNIapp实现局域网内在线升级的操作方法

    UNIapp实现局域网内在线升级的操作方法

    这篇文章主要介绍了UNIapp实现局域网内在线升级的操作方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-03-03

最新评论