我读vue响应式

作者 : 开心源码 本文共3511个字,预计阅读时间需要9分钟 发布时间: 2022-05-12 共188人阅读

vue生命周期:
init:初始化props,methods,data,computed和watch;

1.this是如何直接访问data、props、methods里的属性和方法的?

注:为避免冲突和覆盖,data、props、methods里不能定义相同名字的属性,
优先级:props> methods> data(即假如一个 key 在 props 中有定义了那么就不能在 data 和 methods 中出现了;假如一个 key 在 data 中出现了那么就不能在 methods 中出现了)

源码中的initState函数:

export function initState (vm: Component) {  vm._watchers = []  const opts = vm.$options  if (opts.props) initProps(vm, opts.props)  if (opts.methods) initMethods(vm, opts.methods)  if (opts.data) {    initData(vm)  } else {    observe(vm._data = {}, true /* asRootData */)  }  if (opts.computed) initComputed(vm, opts.computed)  if (opts.watch && opts.watch !== nativeWatch) {    initWatch(vm, opts.watch)  }}

由以上源码可以看到 initState 其实是很多选项初始化的汇总,包括:props、methods、data、computed 和 watch;

2.实现一个简易的响应式系统

Object.defineProperty:在对象上定义或者修改属性
Object.observe:观察对象属性的更改
Vue通过Object.defineProperty的 getter/setter 对收集的依赖项进行监听,在属性被访问和修改时通知变化,进而升级视图数据;
即数据观测、依赖收集、视图升级。

observer的实现

让object的对象都用Object.defineProperty来定义,以达到获取或者修改的时候能够调用属性里的get和set

class Observer {    constructor(value) {        this.value = value         this.walk(this.value)    }    walk (value) {        // 递归遍历value的属性        Object.keys(value).forEach((key) = > {            defineReactive(value, key, value[key])        })    }}// 将对象的每一个属性都增加get和set方法function defineReactive(obj, key ,val) {    let childOb = observe(val)    Obeject.defineProperty(obj, key, {        enumerable: true,        configurable: true,        get() {            console.log('')            return val        },        // 对象改变时,新对象的每个属性也增加get和set方法        set(newVal) {            console.log('set')            val = newVal            childOb = observe(val)        }    })}// 属性类型观测判断function observe (value) {    if (typeof value === 'object' && !Array.isArray(value)) {        value = new Observer(value);        return value;    }}

以上代码可以看出,我们是通过console来判断能否执行get和set的,为了方便,我们使用消息订阅来实现通知变化

Dep的实现

收集属性值的变化,一旦set触发就升级视图

 class Dep {        constructor(){            //订阅的信息            this.subs = [];        }        addSub(sub){            this.subs.push(sub);        }        removeSub (sub) {            remove(this.subs, sub);        }        //升级收集        depend(){            if (Dep.target) {                Dep.target.addDep(this);            }        }        //派发通知        notify(){            const subs = this.subs.slice()            for (let i = 0, l = subs.length; i < l; i++) {                subs[i].update();            }        }    }    // 订阅完成后将target清掉    Dep.target = null;
Watcher的实现

状态发生改变时升级视图

 const watcher = {        addDep:function (dep) {            dep.addSub(this);        },        update:function(){            html();        }    }

以上,我们完成来Observe、Dep、Watcher的简单实现,我们看到Observe和Dep里都调用里Watcher里的update,为了让其各司其职,我们将其改为Observe里一旦触发set就通知Dep并调用notify派发升级任务。

将以上实现进行简单修改和串联,以实现响应式,一律代码如下:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body></body><script>    class Observer {        constructor(value) {            this.value = value;            this.walk(this.value);        }        walk (value) {            // 递归遍历value的属性            Object.keys(value).forEach((key) => {                defineReactive(value, key, value[key]);            })        }    }    // 将对象的每一个属性都增加get和set方法    function defineReactive(obj, key ,val) {        // new一个Dep对象,后面要调用dep的方法        const dep = new Dep();        let val = observe(val);        Object.defineProperty(obj,key,{            enumerable: true,            configurable: true,            get: function () {                if(Dep.target){                    //收集依赖                    dep.depend()                }                return val;            },            set: function (newVal) {                if(newVal === val || (newVal !== newVal && val !== val)){                    return ;                }                val = observe(newVal);                //发布改变                dep.notify();            }        });    }    // 属性类型观测判断    function observe (value) {        if (typeof value === 'object' && !Array.isArray(value)) {            value = new Observer(value);            return value;        }    }    class Dep {        constructor(){            //订阅的信息            this.subs = [];        }        addSub(sub){            this.subs.push(sub);        }        removeSub (sub) {            remove(this.subs, sub);        }        //此方法的作用等同于 this.subs.push(Watcher);        depend(){            if (Dep.target) {                Dep.target.addDep(this);            }        }        //这个方法就是发布通知了 告诉你 有改变啦        notify(){            const subs = this.subs.slice()            for (let i = 0, l = subs.length; i < l; i++) {                subs[i].update();            }        }    }    // 订阅完成后将target清掉    Dep.target = null;    const watcher = {        addDep:function (dep) {            dep.addSub(this);        },        update:function(){            html();        }    }    let obj = {        a: '仔细看'    };    function html () {        document.querySelector('body').innerHTML = obj.a;    }    Dep.target = watcher;    html();//第一次渲染界面    Dep.target = null;    setTimeout(function() {        obj.a = '我变了';        html();    },5000)    </script>

注:主要修改都在defineReactive里,以上代码可直接运行。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 我读vue响应式

发表回复