vue原理解析

1.kvue.js 

class KVue{
    constructor(options){
        this.$options=options
        this.$data = options.data
        observe(options.data)
        proxy(this,'$data')

        //创建编译器
        new Compile(options.el,this)
    }
}
class Observe{
    constructor(value){
        this.value=value
        //判断类型
        if(typeof value==='object'){
            this.walk(value)
        }
    }
    //对象数据响应化
    walk(obj){
        Object.keys(obj).forEach(key=>{
            defineReactive(obj,key,obj[key])
        })
    }
}
function defineReactive(obj,key,value){
    observe(value)

    //创建一个Dep和当前的key一一对应
    const dep = new Dep()
    Object.defineProperty(obj,key,{
        get(){
            //依赖收集
            Dep.target&&dep.addDep(Dep.target)
            return value
        },
        set(newVal){
            if(newVal!==value){
                //如果newVal为obj,需要进行响应式处理
                // console.log('set['+key+'->'+newVal+']')
                observe(newVal)
                value=newVal
                dep.notify()
            }
        }
    })
}
function observe(obj){
    if(typeof obj!=='object'||obj===null){
        return 
    }
    //创建Observe实例
    new Observe(obj)
}
//代理函数,方便用户访问$data中的数据
function proxy(vm){
    Object.keys(vm.$data).forEach(key=>{
        Object.defineProperty(vm,key,{
            get(){
                return vm.$data[key]
            },
            set(newVal){
                vm.$data[key] =newVal
            }
        })
    })
}

2.compile.js

//递归遍历dom树
// 判断节点类型,如果是文本,判断是否为插值绑定,若果是元素,则遍历其属性判断是否是指令或事件,递归子元素
class Compile{
    //el为宿主元素
    //vm是KVue实例
    constructor(el,vm){
        this.$vm = vm
        this.$el=document.querySelector(el)
        if(this.$el){
            this.compile(this.$el)
        }
    }
    compile(el){
        //遍历el树
        const childNodes=el.childNodes;
        Array.from(childNodes).forEach(node=>{
            //判断类型
            if(this.isElement(node)){
                this.compileElement(node)
            }else if(this.isInter(node)){ //插值绑定
                this.compileText(node)
            }
            //递归子节点
            if(node.childNodes&&node.childNodes.length>0){
                this.compile(node)
            }
        })
    }
    isElement(node){
        return node.nodeType===1
    }
    isInter(node){
        //首先是文本标签,其次内容是{{text}}
        return node.nodeType===3&&/\{\{(.*)\}\}/.test(node.textContent)
    }
    compileText(node){
        // node.textContent=this.$vm[RegExp.$1]
        this.update(node,RegExp.$1,'text')
    }
    compileElement(node){
        //遍历当前节点的属性列表
        const nodeAttrs = node.attributes
        Array.from(nodeAttrs).forEach(attr=>{
            //规定:指令以k-name定义
            const attrName =attr.name
            const exp = attr.value
            if(this.isDirective(attrName)){
                const dir = attrName.substring(2)
                //执行指令
                this[dir]&&this[dir](node,exp)
            }
        })
    }
    isDirective(attr){
        return attr.indexOf('k-')===0
    }
    text(node,exp){
        // node.textContent = this.$vm[exp]
        this.update(node,exp,'text')
    }
    html(node,exp){
        this.update(node,exp,'html')
        // node.innerHTML = this.$vm[exp]
    }
    update(node,exp,dir){
        //初始化操作
        //指令对应的更新函数
        const fn = this[dir+'Update']
        fn&&fn(node,this.$vm[exp])
        //更新处理可以更新对应的dom元素
        new Watcher(this.$vm,exp,function(val){
            fn&&fn(node,val)
        })
    }
    textUpdate(node,value){
        node.textContent=value
    }
    htmlUpdate(node,value){
        node.innerHTML = value
    }
}

3.watcher.js

//观察者:保存根性函数
// const watchers = []
class Watcher{
    constructor(vm,key,updatefn){
        this.vm=vm
        this.key=key
        this.updatefn = updatefn
        // watchers.push(this)
        //Dep.target静态属性上设置为当前watcher实例
        Dep.target=this
        this.vm[this.key] //读取触发了getter
        Dep.target =null //收集完防控
    }
    update(){
        this.updatefn.call(this.vm,this.vm[this.key])
    }
}

4.dep.js

//管理依赖,管理某个key相关的所有watcher实例
class Dep{
    constructor(){
        this.deps=[]
    }
    addDep(dep){
        this.deps.push(dep)
    }
    notify(){
        this.deps.forEach(dep=>dep.update())
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值