vue源码系列07_watch属性

state.js

在该方法中,保存了vue实例初始的5种属性,我们找到watch属性的位置,编写其方法即可

import { observe } from './observer/index.js'
import Watcher from './watcher.js';
import Dep from './observer/dep.js';
export function initState(vm) {
    const opts = vm.$options;
    // vue的数据来源 属性 方法 数据 计算属性 watch
    if (opts.props) {
        initProps(vm);
    }
    if (opts.methods) {
        initMethod(vm);
    }
    if (opts.data) {
        initData(vm);
    }
    if (opts.computed) {
        initComputed(vm, opts.computed);
    }
    if (opts.watch) {
        initWatch(vm);
    }
}

function initProps() { }
function initMethod() { }

function proxy(vm, source, key) {
    Object.defineProperty(vm, key, { // 给vm添加了监听属性
        get() {
            return vm[source][key]
        },
        set(newValue) {
            return vm[source][key] = newValue
        }
    })
}

function initData(vm) {
    // 数据初始化工作
    let data = vm.$options.data; //用户传递的data
    data = vm._data = typeof data === 'function' ? data.call(vm) : data; //如果data是一个函数,就直接执行,并把this指向vue实例,否则就获取data对象
    // 对象劫持,用户改变了数据 我希望可以得到通知 => 刷新页面
    // MVVM 模式 数据变化驱动视图变化
    // Object.defineProperty() 给属性添加get方法和set方法

    for (let key in data) {
        proxy(vm, "_data", key)
    }


    observe(data); // 响应式原理
}
function initComputed(vm, computed) {}
function initWatch(vm) {}

$watch

在原型上添加该方法,用于创建watcher

Vue.prototype.$watch = function(key,handler) {
     let vm = this
     new Watcher(vm,key,handler,{user:true}) // user:true 代表是用户单独调用
 }

修改watcher

  1. 主要是判断 exprOrFn 是否为函数,由于我们传入的是key并非函数,所以我们得编写getValue方法,取出value
  2. 修改get() 方法,返回一个老值
  3. 修改run()方法, 判断新值是否相等于老值,如果不相等,就触发cb(用户写在watch里的函数)
import { pushTarget, popTarget } from "./observer/dep";
import { util } from "./utils/index";

let id = 0
class Watcher {
    constructor(vm, exprOrFn, cb = () => { }, opts) {
        this.vm = vm
        this.exprOrFn = exprOrFn
        this.cb = cb
        this.id = id++
        this.deps = []
        this.depsId = new Set()
        if (opts && opts.lazy) {
            this.lazy = opts.lazy
        }
        this.dirty = this.lazy // 缓存属性
        if (typeof exprOrFn === 'function') {
            this.getter = exprOrFn
        } else {
            // 现在 exprOrFn 是我们传进来的key
            this.getter = function () {
                return util.getValue(vm, exprOrFn)
            }
        }
        this.value = this.lazy ? undefined : this.get() // 获取老值
        if (opts && opts.user) {
            this.user = true
        }
        // 如果当前是我们的计算属性的话 不会默认调用get方法
    }
    evalValue() {
        this.value = this.get()
        this.dirty = false; //第二次计算的时候走缓存
    }
    get() {
        pushTarget(this)
        let value = this.getter.call(this.vm)
        popTarget()
        return value // 返回老值
    }
    update() {
        if (this.lazy) {
            this.dirty = true
        } else {
            queueWatcher(this)
        }
        // this.get()
    }
    run() {
        let value = this.get(); //获取新值
        if (this.value !== value) {
            this.cb(value, this.value)
        }
    }
    addDep(dep) {
        let id = dep.id
        // 当该watcher没有相同的 dep
        if (!this.depsId.has(id)) {
            this.depsId.add(id)
            this.deps.push(dep)
            dep.addSub(this)
        }
    }
    depend() {
        let i = this.deps.length
        while(i--){
            this.deps[i].depend()
        }
    }
}
let has = {}
let queue = [];

function flusqueue() {
    queue.forEach(watcher => watcher.run())
    has = {};
    queue = []
}
function queueWatcher(watcher) {
    let id = watcher.id
    if (has[id] == null) {
        has[id] = true
        queue.push(watcher)
    }
    nextTick(flusqueue)
}

// 异步执行
let callbacks = [];

function flushCallbacks() {
    callbacks.forEach(cb => cb())
}
function nextTick(flusqueue) {
    callbacks.push(flusqueue)
    let asyncFn = () => {
        flushCallbacks()
    }
    if (Promise) {
        Promise.resolve().then(asyncFn)
    }
    setTimeout(asyncFn, 0)
}

export default Watcher

initWatch()

工作步骤:

  1. 获取watch属性
  2. 将watch的值取出
  3. 给每个值创建对应的watcher
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值