溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

vue中complie數(shù)據(jù)雙向綁定原理

發(fā)布時間:2021-08-23 10:40:40 來源:億速云 閱讀:146 作者:chen 欄目:編程語言

這篇文章主要介紹“vue中complie數(shù)據(jù)雙向綁定原理”,在日常操作中,相信很多人在vue中complie數(shù)據(jù)雙向綁定原理問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”vue中complie數(shù)據(jù)雙向綁定原理”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

vue數(shù)據(jù)雙向綁定原理,和簡單的實現(xiàn),本文將實現(xiàn)mvvm的模板指令解析器

vue中complie數(shù)據(jù)雙向綁定原理

1)vue數(shù)據(jù)雙向綁定原理-observer

2)vue數(shù)據(jù)雙向綁定原理-wather

3)vue數(shù)據(jù)雙向綁定原理-解析器 Complie

vue數(shù)據(jù)雙向綁定原理,和簡單的實現(xiàn),本文將實現(xiàn)mvvm的模板指令解析器

上一步實現(xiàn)了簡單數(shù)據(jù)綁定,最后實現(xiàn)解析器,來解析v-model,v-on:click等指令,和{{}}模板數(shù)據(jù)。解析器Compile實現(xiàn)步驟:

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

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

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

function node2Fragment(el) {
  var fragment = document.createDocumentFragment(),
    child;
  // 將原生節(jié)點拷貝到fragment
  while ((child = el.firstChild)) {
    fragment.appendChild(child);
  }

  return fragment;
}

接下來渲染'{{}}'模板

//Compile
function Compile(el, vm) {
  this.$vm = vm;
  this.$el = this.isElementNode(el) ? el : document.querySelector(el);
  if (this.$el) {
    this.$fragment = this.node2Fragment(this.$el);
    this.init();
    this.$el.appendChild(this.$fragment);
  }
}

Compile.prototype = {
  init: function () {
    this.compileElement(this.$fragment);
  },

  node2Fragment: function (el) {
    //...
  },

  //編譯模板
  compileElement: function (el) {
    var childNodes = el.childNodes,
      self = this;
    [].slice.call(childNodes).forEach(function (node) {
      var text = node.textContent;
      var reg = /{{(.*)}}/; //表達式文本
      //按元素節(jié)點方式編譯
      if (self.isElementNode(node)) {
        self.compile(node);
      } else if (self.isTextNode(node) && reg.test(text)) {
        self.compileText(node, RegExp.$1);
      }
      //遍歷編譯子節(jié)點
      if (node.childNodes && node.childNodes.length) {
        self.compileElement(node);
      }
    });
  },

  isElementNode: function (node) {
    return node.nodeType == 1;
  },

  isTextNode: function (node) {
    return node.nodeType == 3;
  },

  compileText: function (node, exp) {
    var self = this;
    var initText = this.$vm[exp];
    this.updateText(node, initText);
    new Watcher(this.$vm, exp, function (value) {
      self.updateText(node, value);
    });
  },

  updateText: function (node, value) {
    node.textContent = typeof value == "undefined" ? "" : value;
  },
};

處理解析指令對相關(guān)指令進行函數(shù)綁定。

Compile.prototype = {

  ......
  isDirective: function(attr) {
    return attr.indexOf('v-') == 0;
  },

  isEventDirective: function(dir) {
    return dir.indexOf('on:') === 0;
  },

  //處理v-指令
  compile: function(node) {

    var nodeAttrs = node.attributes,
      self = this;
    [].slice.call(nodeAttrs).forEach(function(attr) {
      // 規(guī)定:指令以 v-xxx 命名
      // 如 <span v-text="content"></span> 中指令為 v-text
      var attrName = attr.name; // v-text
      if (self.isDirective(attrName)) {
        var exp = attr.value; // content
        var dir = attrName.substring(2); // text
        if (self.isEventDirective(dir)) {
          // 事件指令, 如 v-on:click
          self.compileEvent(node, self.$vm, exp, dir);
        } else {
          // 普通指令如:v-model, v-html, 當前只處理v-model
          self.compileModel(node, self.$vm, exp, dir);
        }
        //處理完畢要干掉 v-on:, v-model 等元素屬性
        node.removeAttribute(attrName)
      }
    });

  },

  compileEvent: function(node, vm, exp, dir) {

    var eventType = dir.split(':')[1];
    var cb = vm.$options.methods && vm.$options.methods[exp];
    if (eventType && cb) {
      node.addEventListener(eventType, cb.bind(vm), false);
    }

  },

  compileModel: function(node, vm, exp, dir) {

    var self = this;
    var val = this.$vm[exp];
    this.updaterModel(node, val);
    new Watcher(this.$vm, exp, function(value) {
      self.updaterModel(node, value);
    });
    node.addEventListener('input', function(e) {
      var newValue = e.target.value;
      if (val === newValue) {
        return;
      }
      self.$vm[exp] = newValue;
      val = newValue;
    });

  },

  updaterModel: function(node, value, oldValue) {
    node.value = typeof value == 'undefined' ? '' : value;
  },

}

最后再關(guān)聯(lián)起來

function Vue(options) {
  .....
  observe(this.data, this);
  this.$compile = new Compile(options.el || document.body, this)
  return this;

}

來嘗試下效果

<!--html-->
<div id="app">
  <h3>{{name}}</h3>
  <input v-model="name" />
  <h2>{{name}}</h2>
  <button v-on:click="test">click here!</button>
</div>
<script>
  new Vue({
    el: "#app",
    data: {
      name: "chuchur",
      age: 29,
    },
    methods: {
      test() {
        this.name = "My name is chuchur";
      },
    },
  });
</script>

到此,關(guān)于“vue中complie數(shù)據(jù)雙向綁定原理”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI