国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Vue雙向綁定的實現(xiàn)原理系列(四):補充指令解析器compile

cheukyin / 2068人閱讀

摘要:補充指令解析器源碼補充下節(jié)點類型的知識元素節(jié)點屬性節(jié)點文本節(jié)點節(jié)點實體引用名稱節(jié)點實體名稱節(jié)點處理指令節(jié)點注釋節(jié)點文檔節(jié)點文檔類型節(jié)點文檔片段節(jié)點聲明節(jié)點指令解析器解析節(jié)點,直接固定某個節(jié)點進行替換數(shù)據(jù)的解析模板指令,替換模板數(shù)據(jù)初始化試圖

補充指令解析器compile

github源碼

補充下HTML節(jié)點類型的知識:
    元素節(jié)點              Node.ELEMENT_NODE(1)
    屬性節(jié)點              Node.ATTRIBUTE_NODE(2)
    文本節(jié)點              Node.TEXT_NODE(3)
    CDATA節(jié)點             Node.CDATA_SECTION_NODE(4)
    實體引用名稱節(jié)點       Node.ENTRY_REFERENCE_NODE(5)
    實體名稱節(jié)點          Node.ENTITY_NODE(6)
    處理指令節(jié)點          Node.PROCESSING_INSTRUCTION_NODE(7)
    注釋節(jié)點              Node.COMMENT_NODE(8)
    文檔節(jié)點              Node.DOCUMENT_NODE(9)
    文檔類型節(jié)點          Node.DOCUMENT_TYPE_NODE(10)
    文檔片段節(jié)點          Node.DOCUMENT_FRAGMENT_NODE(11)
    DTD聲明節(jié)點            Node.NOTATION_NODE(12)

Compile指令解析器,解析DOM節(jié)點,直接固定某個節(jié)點進行替換數(shù)據(jù)的

解析模板指令,替換模板數(shù)據(jù),初始化試圖

將模板指令對應(yīng)的節(jié)點綁定對應(yīng)的更新函數(shù),初始化對應(yīng)的訂閱器

首先需要獲取到DOM元素,然后對含有DOM元素上含有指令的節(jié)點進行處理,
因此這個環(huán)節(jié)需要對DOM操作比較頻繁,所有可以先建一個fragment片段,
將需要解析的DOM節(jié)點存入fragment片段里再進行處理:

//直接上代碼:(先判斷"{{}}")
    function Compile(elm){// el->"#name" ,vm->{el:;data:;}
        this.vm = elm;
        this.el = document.querySelector(elm.el);
        this.fragment = null;
        this.init();
    }
    Compile.prototype = {
        init:function(){
            if(this.el) {
                //將需要解析的DOM節(jié)點存入fragment片段里再進行處理
                this.fragment = this.nodeToFragment(this.el);
                
                //接下來遍歷各個節(jié)點,對含有指定的節(jié)點特殊處理,先處理指令“{{}}”:
                this.compileElement(this.fragment);
                
                //綁定到el上
                this.el.appendChild(this.fragment);
            }else{
                console.log("DOM元素不存在");
            }
        },
        //創(chuàng)建代碼片段
        nodeToFragment:function(el){
            var fragment = document.createDocumentFragment();
            var child = el.firstChild;
            while(child){//將DOM元素移入fragment
                fragment.appendChild(child);
                child = el.firstChild;
            }
            return fragment;
        },
         //對所有子節(jié)點進行判斷,1.初始化視圖數(shù)據(jù),2.綁定更新函數(shù)的訂閱器
        compileElement:function(el){
            var childNodes = el.childNodes;
            var self = this;
            [].slice.call(childNodes).forEach(function(node){
                var reg = /{{(.*)}}/;//匹配" {{}} "
                var text = node.textContent;
    
                if(self.isTextNode(node) && reg.test(text)) {//判斷" {{}} "
                    self.compileText(node,reg.exec(text)[1]);
                }
    
                if(node.childNodes && node.childNodes.length){
                    self.compileElement(node);//// 繼續(xù)遞歸遍歷子節(jié)點
                }
            });
        },
        //初始化視圖updateText和生成訂閱器:
        compileText:function(node,exp){
            var self = this;
            var initText = this.vm[exp];   //代理訪問self_vue.data.name1 -> self_vue.name1
            this.updateText(node,initText);//將初始化的數(shù)據(jù)初始化到視圖中
            new Watcher(this.vm,exp,function(value){//{},name, // 生成訂閱器并綁定更新函數(shù)
                self.updateText(node,value);
            })
        },
        updateText: function (node, value) {
            node.textContent = typeof value == "undefined" ? "" : value;
        },
        isTextNode:function(node){
            return node.nodeType == 3;//文本節(jié)點
        }
    };

為了將解析器Compile與監(jiān)聽器Observer和訂閱者Watcher關(guān)聯(lián)起來,我們需要再修改一下類SelfVue函數(shù):

 // function SelfVue(data,el,exp){  //first
    function SelfVue(options){
        var self = this;
    
        // this.data = data;  //first
        this.data = options.data;
        this.el = options.el;
    
        this.vm = this; //second
        console.log(this)
    
        Object.keys(this.data).forEach(function (key) {
            self.proxyKeys(key);//綁定代理屬性
        });
    
        //監(jiān)聽數(shù)據(jù):
        observers(this.data);
    
        //first:
        /*el.innerHTML = this.data[exp];//初始化模板數(shù)據(jù)的值
        new Watcher(this,exp,function(value){//綁定訂閱器
            el.innerHTML = value;
        });*/
    
        //初始化視圖updateText和生成訂閱器
        new Compile(this);
    
        return this;
    }

到這里,大括號"{{}}"類型的雙向數(shù)據(jù)綁定完成;

補充上v-model和事件指令:

在compileElement函數(shù)加上對其他指令節(jié)點進行判斷,然后遍歷其所有屬性

添加事件指令

添加一個v-model指令

  Compile.prototype = {
      init:function(){
          if(this.el) {
              //將需要解析的DOM節(jié)點存入fragment片段里再進行處理
              this.fragment = this.nodeToFragment(this.el);
  
              //接下來遍歷各個節(jié)點,對含有指定的節(jié)點特殊處理,先處理指令“{{}}”:
              this.compileElement(this.fragment);
  
              //綁定到el上
              this.el.appendChild(this.fragment);
          }else{
              console.log("DOM元素不存在");
          }
      },
      //創(chuàng)建代碼片段
      nodeToFragment:function(el){
          var fragment = document.createDocumentFragment();
          var child = el.firstChild;
          while(child){//將DOM元素移入fragment
              fragment.appendChild(child);
              child = el.firstChild;
          }
          return fragment;
      },
      //對所有子節(jié)點進行判斷,1.初始化視圖數(shù)據(jù),2.綁定更新函數(shù)的訂閱器
      compileElement:function(el){
          var childNodes = el.childNodes;
          var self = this;
          [].slice.call(childNodes).forEach(function(node){
              var reg = /{{(.*)}}/;//匹配" {{}} "
              var text = node.textContent;
/*      補充判斷:     */
              if(self.isElementNode(node)){//元素節(jié)點判斷
                  self.compile(node);
              }else if(self.isTextNode(node) && reg.test(text)) {//文本節(jié)點判斷 ,判斷" {{}} "
                  self.compileText(node,reg.exec(text)[1]);
              }
  
              if(node.childNodes && node.childNodes.length){
                  self.compileElement(node);//// 繼續(xù)遞歸遍歷子節(jié)點
              }
          });
      },
      //初始化視圖updateText和生成訂閱器:
      compileText:function(node,exp){
          var self = this;
          var initText = this.vm[exp];   //代理訪問self_vue.data.name1 -> self_vue.name1
          this.updateText(node,initText);//將初始化的數(shù)據(jù)初始化到視圖中
          new Watcher(this.vm,exp,function(value){//{},name, // 生成訂閱器并綁定更新函數(shù)
              self.updateText(node,value);
          })
      },
      updateText: function (node, value) {
          node.textContent = typeof value == "undefined" ? "" : value;
      },
      compile:function(node){
          var nodeAttrs = node.attributes;
          var self = this;
          Array.prototype.forEach.call(nodeAttrs,function(attr){
              var attrName = attr.name;
              if(self.isDirective(attrName)){//查到" v- "
                  var exp = attr.value;
                  var dir = attrName.substring(2);//" v-on/v-model "
  
                  if(self.isEventDirective(dir)){ // 事件指令
                      self.compileEvent(node,self.vm,exp,dir);
                  }else{
                      self.compileModel(node,self.vm,exp,dir);
                  }
                  node.removeAttribute(attrName);
              }
          })
      },
      compileEvent:function(node,vm,exp,dir) {//代碼片段<><>,{data:;vm:;el:;},v-on="add",on:
          var eventType = dir.split(":")[1];//on
          var cb = vm.methods && vm.methods[exp];
  
          if(eventType && cb){
              node.addEventListener(eventType,cb.bind(vm),false);
          }
      },
      compileModel:function(node,vm,exp,dir){//代碼片段<><>,{data:;vm:;el:;},v-on="addCounts",model:
          var self = this;
          var val = this.vm[exp];
          this.modelUpdater(node,val);
          new Watcher(this.vm,exp,function(value){
              self.modelUpdater(node,value);
          });
  
          node.addEventListener("input",function(e){
              var newValue = e.target.value;
              if(val === newValue){
                  return;
              }
              self.vm[exp] = newValue;
              val = newValue;
          })
      },
      modelUpdater:function(node,value){
          node.value = typeof value == "undefined" ? "" : value;
      },
      isTextNode:function(node){
          return node.nodeType == 3;//文本節(jié)點
      },
      isElementNode:function(node){
          return node.nodeType == 1;//元素節(jié)點

}, isDirective:function(attr){//查找自定義屬性為:v- 的屬性 return attr.indexOf("v-") == 0; }, isEventDirective:function(dir){ // 事件指令 return dir.indexOf("on:") === 0 } };

再改造下類SelfVue,使它更像Vue的用法:

    function SelfVue(options){
        var self = this;
        this.data = options.data;
        this.el = options.el;
        this.methods = options.methods;
    
        this.vm = this; //second
    
        Object.keys(this.data).forEach(function (key) {
            self.proxyKeys(key);//綁定代理屬性
        });
    
        //監(jiān)聽數(shù)據(jù):
        observers(this.data);
     
        //初始化視圖updateText和生成訂閱器
        new Compile(this);
        options.mounted.call(this);
    
        return this;
    }

測試:


{{name1}}

{{name2}}

{{title}}

{{event}}

系列文章的目錄:

Vue雙向綁定的實現(xiàn)原理系列(一):Object.defineproperty
Vue雙向綁定的實現(xiàn)原理系列(二):設(shè)計模式
Vue雙向綁定的實現(xiàn)原理系列(三):監(jiān)聽器Observer和訂閱者Watcher
Vue雙向綁定的實現(xiàn)原理系列(四):補充指令解析器compile

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/107276.html

相關(guān)文章

  • Vue雙向綁定實現(xiàn)原理系列):補充指令解析compile

    摘要:補充指令解析器源碼補充下節(jié)點類型的知識元素節(jié)點屬性節(jié)點文本節(jié)點節(jié)點實體引用名稱節(jié)點實體名稱節(jié)點處理指令節(jié)點注釋節(jié)點文檔節(jié)點文檔類型節(jié)點文檔片段節(jié)點聲明節(jié)點指令解析器解析節(jié)點,直接固定某個節(jié)點進行替換數(shù)據(jù)的解析模板指令,替換模板數(shù)據(jù)初始化試圖 補充指令解析器compile github源碼 補充下HTML節(jié)點類型的知識: 元素節(jié)點   Node.ELEMEN...

    Kylin_Mountain 評論0 收藏0
  • Vue雙向綁定實現(xiàn)原理系列(三):監(jiān)聽Observer和訂閱者Watcher

    摘要:至此監(jiān)聽器和訂閱者功能基本完成,后面再加上指令解析器的功能系列文章的目錄雙向綁定的實現(xiàn)原理系列一雙向綁定的實現(xiàn)原理系列二設(shè)計模式雙向綁定的實現(xiàn)原理系列三監(jiān)聽器和訂閱者雙向綁定的實現(xiàn)原理系列四補充指令解析器 監(jiān)聽器Observer和訂閱者Watcher 實現(xiàn)簡單版Vue的過程,主要實現(xiàn){{}}、v-model和事件指令的功能 主要分為三個部分 github源碼 1.數(shù)據(jù)監(jiān)聽器Obser...

    widuu 評論0 收藏0
  • Vue雙向綁定實現(xiàn)原理系列(三):監(jiān)聽Observer和訂閱者Watcher

    摘要:至此監(jiān)聽器和訂閱者功能基本完成,后面再加上指令解析器的功能系列文章的目錄雙向綁定的實現(xiàn)原理系列一雙向綁定的實現(xiàn)原理系列二設(shè)計模式雙向綁定的實現(xiàn)原理系列三監(jiān)聽器和訂閱者雙向綁定的實現(xiàn)原理系列四補充指令解析器 監(jiān)聽器Observer和訂閱者Watcher 實現(xiàn)簡單版Vue的過程,主要實現(xiàn){{}}、v-model和事件指令的功能 主要分為三個部分 github源碼 1.數(shù)據(jù)監(jiān)聽器Obser...

    legendaryedu 評論0 收藏0
  • Vue雙向綁定實現(xiàn)原理系列(一):Object.defineproperty

    摘要:并且,由于是在不同的數(shù)據(jù)上觸發(fā)同步,可以精確的將變更發(fā)送給綁定的視圖,而不是對所有的數(shù)據(jù)都執(zhí)行一次檢測。默認(rèn)值為表示能否修改屬性的值。 了解Object.defineProperty() github源碼 Object.defineProperty()方法直接在一個對象上定義一個新屬性,或者修改一個已經(jīng)存在的屬性, 并返回這個對象。 vueJS采用 ES5 提供的 Object....

    crossoverJie 評論0 收藏0
  • Vue雙向綁定實現(xiàn)原理系列(一):Object.defineproperty

    摘要:并且,由于是在不同的數(shù)據(jù)上觸發(fā)同步,可以精確的將變更發(fā)送給綁定的視圖,而不是對所有的數(shù)據(jù)都執(zhí)行一次檢測。默認(rèn)值為表示能否修改屬性的值。 了解Object.defineProperty() github源碼 Object.defineProperty()方法直接在一個對象上定義一個新屬性,或者修改一個已經(jīng)存在的屬性, 并返回這個對象。 vueJS采用 ES5 提供的 Object....

    bluesky 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<