模仿vue手写一个mvvm框架

VUE是现在最流行的前端框架了;想学习源码的要先写一个基础框架;
这样源码学习起来就纵享丝滑了

//wather和依赖收集器    不依赖key值生成对应的dep
//利用ES6的Proxy来 get收集依赖;set发布  

class MyVue{
    constructor(options){
        this.$options=options;
        this.$data=options.data;
        this.observe(this.$data)
        this.compile()
    }
    observe(data){//使用difinepeoperty实现数据对象监听----观察数据,劫持数据
        let objDep={}
        Object.keys(data).forEach(key=>{
            objDep[key]=new Dep()
        })
        this.$data=new Proxy(data,{
            get(target,key){
                if(Dep.target){
                    objDep[key].addSub(Dep.target)
                }
                
                return target[key]
            },
            set(target,key,newValue){
                objDep[key].notify(newValue)

                target[key]=newValue
                return true
            }
        })
//使用proxy改写下面的 defineproperty

        // Object.keys(data).forEach(key=>{
        //     let value=data[key]//先保存起来防止下面defineProperty的调用进入死循环
        //     let _this=this
        //     let dep=new Dep()
        //     Object.defineProperty(data,key,{
        //         configurable:true,
        //         enumerable:true,
        //         get(){//get收集依赖;set发布  
        //             console.log('get数据',value)
        //             if(Dep.target){
        //                 dep.addSub(Dep.target)
        //             }
        //             return value
        //         },
        //         set(newVal){//set发布  触发对应的update方法
        //             console.log('set数据',value)
        //             dep.notify(newVal)
        //             value=newVal
        //         }
        //     })
        // })
        
    }
    compile(){
        let ele=document.querySelector(this.$options.el)
        this.compileChildnodes(ele)
    }
    compileChildnodes(ele){
        let childNodes=ele.childNodes;
        let reg=/\{\{\s*([^\{\}\s]+)\s*\}\}/g
        childNodes.forEach(node => {
            let textContent=node.textContent;
            if(node.nodeType===3){
                if(reg.test(textContent)){
                    let $1=RegExp.$1
                    // console.log(this.$data[$1])
                    new Watcher(this.$data,$1,(newval)=>{
                        let oldVal=this.$data[$1]
                        let reg=new RegExp(oldVal)
                        node.textContent=node.textContent.replace(reg,newval)//这里将来要做优化;现在bug多次输入input会重复增加----感觉是new Watcher过多执行问题
                    })
                    node.textContent=node.textContent.replace(reg,this.$data[$1])
                }
            }else if(node.nodeType===1){
                //处理input双向数据绑定问题 v-model
                let attrs=node.attributes;
                [...attrs].forEach(attr=>{
                    let attrname=attr.name
                    let attrValue=attr.value
                    if(attrname === 'v-model'){
                        node.value=this.$data[attrValue]
                        node.addEventListener('input',e=>{
                            this.$data[attrValue]=e.target.value
                        })
                    }else if(attrname==='v-html'){
                        node.innerHTML=this.$data[attrValue]
                    }
                })
                if(node.childNodes.length>0){
                    this.compileChildnodes(node)
                }
            }
        });
    }
}

//依赖收集器;
class Dep{
    constructor(){
        this.subs=[]
    }
    addSub(sub){
        this.subs.push(sub)
    }
    notify(newval){
        this.subs.forEach(e=>{
            e.update(newval)
        })
    }
}

//订阅者
class Watcher{
    constructor(data,key,cb){
        Dep.target=this
        this.cb=cb
    }
    update(e){
        this.cb(e)
        console.log('最后更新了')
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农有梦想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值