vue原理代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="./Kvue.js" type="text/javascript"></script>
</head>
<body>
    <div id="app">
        {{   message }}fsdafdsa
        <div>
            <span>
                <span>
                    <span> {{  message  }}</span>
                </span>
            </span>
        </div>
        {{mydata}}
        <div v-html="htmldata" ></div>
        <input v-model="modelData" /> {{modelData}}
    </div>
</body>
<script>
let vm = new Kvue({
    el:"#app",
    data:{
        message:"测试数据1111",
        mydata:"some value",
        htmldata:"html数据",
        modelData:"双绑数据"
    }
})
</script>
class Kvue{
  constructor(option){
    this.option=option;
    this._data=option.data;
    this.observer();
    this.compile();
  }
  //编译
   compile(){
        let ele=document.querySelector(this.option.el);
        let childNodes=ele.childNodes;
        this.compileNode(childNodes);
    
    }
  //对数据编译到元素上
  compileNode(childNodes){
        let textContent="";
        let exp=null;
        childNodes.forEach((node,index)=>{
        
            if(node.nodeType==3){
                textContent= node.textContent;
                exp=/\{\{\s*(\S+)\s*\}\}/g;
                if(exp.test(textContent)){
                    // 初次渲染;
                    let $1 = RegExp.$1;
                    node.textContent=this._data[$1];
                
                    new   Watcher(this,$1,newValue=>{
                       node.textContent=newValue;
                    });

                }
            }
            else if(node.nodeType==1){

              let attrs= node.attributes;
                [...attrs].forEach((attr,index)=>{
                 let name= attr.name;
                 let value= attr.value;
                    if(name=="v-model"){
                      node.addEventListener("input",ev=>{
                        this._data[value]=ev.target.value;
                      });
                      new  Watcher(this,value,newValue=>{
                        node.value=newValue;
                    });
                    }
               
                });


               if(node.childNodes.length>0){
                  this.compileNode(node.childNodes);
               } 
            } 
        });   
    }
    observer(){
      Object.keys(this._data).forEach((key)=>{
       
        let dep=new Dep();                                                                                                                                                                                                   
        let value= this.option.data[key];
        Object.defineProperty(this._data,key,{
           configurable: true,                                                                                                                                                                                                         
            enumerable: true,
            get(){
              if(Dep.target){
                 dep.addSub(Dep.target);
              }
              return value;
            },
            set(newValue){
           
              if(value!=newValue){
         
                dep.notify(newValue);
                value=newValue;
              }
            }
        });
      })
    }
}
//发布订阅 Dep 类和 Watcher
class Dep{
  constructor(){
    this.subs=[];
  }
  addSub(sub) {//订阅事件
    this.subs.push(sub);
  }
  notify(newValue) {//通知触发方法
      this.subs.forEach(v => {
          v.update(newValue);
      })
  }
}
class Watcher {
  constructor(vm, exp, cb) {
      Dep.target = this;
      vm._data[exp];
      this.cb = cb;
      Dep.target = null
  }
  update(newValue) {
      this.cb(newValue);
  }
}

 

posted @ 2019-09-02 21:02  a魏国  阅读(188)  评论(0编辑  收藏  举报