当前位置: 代码迷 >> 综合 >> Vue.watch 源码实现
  详细解决方案

Vue.watch 源码实现

热度:42   发布时间:2023-12-05 14:46:14.0

watch

vm.$watch(expOrFn,callback,[options])
功能

观察Vue实例变化的一个表达式或计算属性函数。回调函数得到的参数为新值和旧值。表达式值接收监督的键路径

参数

  • exOrFn:要监视的$data 中的属性,可以说表达式或函数
  • callback:数据变化后执行的函数
    函数:回调函数
    对象:具有handler属性(字符串或者函数),如果该属性为字符串则methods中相应的定义
  • options:可选的选项
    deep: 布尔类型,深度监听
    immediate: 布尔类型,是否立即执行一次回调函数

示例

const vm = new Vue({
    el:"#app",data:{
    user:{
    fisrtName: 'aaaa',lastName: 'bbbbb'}}
})vm.$watch('user',function(newValue,oldValue){
    this.user.firstName = newValue.firstName + " " + newValue.lastName
},{
    immediate: true,deep: true
})

三种类型的Watcher对象

  • 没有静态方法,因为$watch方法中要是用Vue的实例
  • Watcher分三种:计算属性Watcher,用户Watcher(侦听器)、渲染Watcher
    创建顺序:计算属性Watcher,用于Watcher,渲染Watcher
  • vm.$watch()
    src/core/instance/state.js
    部分代码
export function initState (vm: Component) {
    vm._watchers = []const opts = vm.$optionsif (opts.props) initProps(vm, opts.props) // 初始化props,并且通过defineReactive函数将值转换为set,getif (opts.methods) initMethods(vm, opts.methods) // 将选项中的methods注入到vue实例,if (opts.data) {
    initData(vm) // } else {
    observe(vm._data = {
    }, true /* asRootData */) //转换成响应式数据}  if (opts.computed) initComputed(vm, opts.computed)  // 初始化computedif (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)  // 初始化watch}
}function initWatch (vm: Component, watch: Object) {
    for (const key in watch) {
    const handler = watch[key]if (Array.isArray(handler)) {
    for (let i = 0; i < handler.length; i++) {
    createWatcher(vm, key, handler[i])}} else {
    createWatcher(vm, key, handler)}}
}function createWatcher (vm: Component,expOrFn: string | Function,handler: any,options?: Object
) {
    if (isPlainObject(handler)) {
     // hundler是回调函数,就是对应传入方法options = handlerhandler = handler.handler}if (typeof handler === 'string') {
    handler = vm[handler]}return vm.$watch(expOrFn, handler, options)
}export function stateMixin (Vue: Class<Component>) {
    // flow somehow has problems with directly declared definition object// when using Object.defineProperty, so we have to procedurally build up// the object here.const dataDef = {
    }dataDef.get = function () {
     return this._data }const propsDef = {
    }propsDef.get = function () {
     return this._props }if (process.env.NODE_ENV !== 'production') {
    dataDef.set = function () {
    warn('Avoid replacing instance root $data. ' +'Use nested data properties instead.',this)}propsDef.set = function () {
    warn(`$props is readonly.`, this)}}Object.defineProperty(Vue.prototype, '$data', dataDef)Object.defineProperty(Vue.prototype, '$props', propsDef)Vue.prototype.$set = setVue.prototype.$delete = delVue.prototype.$watch = function (expOrFn: string | Function,cb: any,options?: Object): Function {
    // 获取 Vue 实例的thisconst vm: Component = thisif (isPlainObject(cb)) {
    // 判断如果 cb 是对象执行createWatcherreturn createWatcher(vm, expOrFn, cb, options)}options = options || {
    }// 标记为用户 watcheroptions.user = true// 创建用户 watcher 对象const watcher = new Watcher(vm, expOrFn, cb, options)// 判断 immediate 对象if (options.immediate) {
    // 立即执行一次cb回调,并把当前值传入try {
    cb.call(vm, watcher.value)} catch (error) {
    handleError(error, vm, `callback for immediate watcher "${
      watcher.expression}"`)}}// 返回取消监听的方法return function unwatchFn () {
    watcher.teardown()}}
}