实现vue2的响应式原理

/**
 * 
 * 基本原理:
 *  1、通过Observer劫持data上的对象并监听data上的所有属性,遍历所有属性,并用Object.defineProperty转化为getter/setter,监听data上属性的的变化
 *  2、将data上的属性挂载到vue的实例上,实例化后可以在vue使用this访问data属性       
 *  3、使用Compiler解析模板
 *  4、Watcher:添加订阅者,访问和修改时update更新视图
 *  5、Depend:addSub管理订阅数据对象,数据变化时notify通知所有数据对象进行视图更新
 */
function myVue(options={}){
    this.$options = options;
    this.$data = typeof this.$options == 'function' ? this.options.data() : this.$options.data;
    this.$el = this.$options.el;
    // 将this.$data添加到响应式系统
    new Observer(this.$data)
    //将data上的属性添加到vue中
    this.$proxy();
    //解析模板
    new Compiler(this.$el,this.$data);
    this.$options.created.call(this);
}
myVue.prototype.$proxy = function () {
    Object.keys(this.$data).forEach(key=>{
        Object.defineProperty(this,key,{
            configurable:true,
            enumerable:true,
            set(val){
                this.$data[key] = val;
            },
            get(){
                return this.$data[key]
            }
        });
    })
}
// 响应式系统
function Observer($data){
    Object.keys($data).forEach(key=>{
        this.$ref($data,key,$data[key])
    })
}
Observer.prototype.$ref = function(_data,key,value){
    let dep = new Depend();
    Object.defineProperty(_data,key,{
        configurable:true,
        enumerable:true,
        set(val){
            if(value===val) return;
            value = val;
            dep.notify();
        },
        get(){
            Depend.target && dep.addSub(Depend.target)       
            return value
        }
    })
}
// 依赖
function Depend(){
    // 订阅者数组
    this.subs = []
}
// 添加订阅者
Depend.prototype.addSub = function(sub){
    this.subs.push(sub)
}
Depend.prototype.notify = function(){
    this.subs.forEach(sub=>{
        sub.update();
    })
}
// 订阅者
function Watcher(node,name,data){
    this.node = node;
    this.name = name;
    this.data = data;
    Depend.target = this;
    this.update();
    Depend.target = null;
}
Watcher.prototype.update = function(){
    if(this.node.nodeType===1){
        this.node.value = this.data[this.name]
    } else if (this.node.nodeType === 3){
        this.node.nodeValue = this.data[this.name]
    }
}
let reg = /\{\{(.+)\}\}/;
// 解析模板
function Compiler(el,data){
    this.el = document.querySelector(el);
    this.data = data;
    let frag = this.createFragment();
    this.el.appendChild(frag);
}
Compiler.prototype.createFragment = function(){
    let child;
    let frag = document.createDocumentFragment();
    while(child = this.el.firstChild){
        this._compiler(child);
        frag.appendChild(child);
    }
    return frag
    
}
Compiler.prototype._compiler = function(node){
    // 标签节点
    if(node.nodeType===1){
        node.childNodes.forEach(item=>{
            this._compiler(item);
        })
    // 文本节点
    }else if(node.nodeType===3){
        if(reg.test(node.nodeValue)){
            const name = reg.exec(node.nodeValue)[1]
            new Watcher(node,name,this.data)
        }

    }
}

 

myVue

posted on 2024-06-18 16:57  久居我梦  阅读(2)  评论(0编辑  收藏  举报

导航