Vue.js學習與理解

Vue.js(讀音 /vjuː/, 相似於 view)是一個構建數據驅動的 web 界面的庫。Vue.js 的目標是經過儘量簡單的 API 實現響應的數據綁定和組合的視圖組件。react

Vue.js 自身不是一個全能框架——它只聚焦於視圖層。所以它很是容易學習,很是容易與其它庫或已有項目整合。另外一方面,在與相關工具和支持庫一塊兒使用時,Vue.js 也能完美地驅動複雜的單頁應用。webpack

Vue.js 的核心是一個響應的數據綁定系統,它讓數據與 DOM 保持同步很是簡單。在使用 jQuery 手工操做 DOM 時,咱們的代碼經常是命令式的、重複的與易錯的。Vue.js 擁抱數據驅動的視圖概念。通俗地講,它意味着咱們在普通 HTML 模板中使用特殊的語法將 DOM 「綁定」到底層數據。一旦建立了綁定,DOM 將與數據保持同步。每當修改了數據,DOM 便相應地更新。這樣咱們應用中的邏輯就幾乎都是直接修改數據了,沒必要與 DOM 更新攪在一塊兒。這讓咱們的代碼更容易撰寫、理解與維護。web

Vue.js比Angular.js react.js簡單,學習成本低。數組

Vue.js使用到二個重要的函數:瀏覽器

1.Object.defineProperty 函數緩存

將屬性添加到對象,或修改現有屬性的特性。框架

Object.defineProperty(object, propertyname, descriptor)
參數
object  必需。  要在其上添加或修改屬性的對象。  這多是一個本機 JavaScript 對象(即用戶定義的對象或內置對象)或 DOM 對象。  
propertyname  必需。  一個包含屬性名稱的字符串。  
descriptor  必需。  屬性描述符。  它能夠針對數據屬性或訪問器屬性。
例子:添加訪問器屬性
 var obj = {},newVal;
 // Add an accessor property to the object.
 Object.defineProperty(obj, "name", {
     set: function (x) {
         console.log("in property set accessor" + newVal);
         this.firstName= x;
     },
     get: function () {
         console.log("in property get accessor" + newVal);
         return this.firstName;
     },
     enumerable: true,
     configurable: true
 });

Vue.js當數據有變化時,經過defineProperty的set方法去通知notify()訂閱者subscribers有新的值修改異步

  function defineReactive(obj, key, val, doNotObserve) {
    var dep = new Dep();

    var property = Object.getOwnPropertyDescriptor(obj, key);
    if (property && property.configurable === false) {
      return;
    }

    // cater for pre-defined getter/setters
    var getter = property && property.get;
    var setter = property && property.set;

    // if doNotObserve is true, only use the child value observer
    // if it already exists, and do not attempt to create it.
    // this allows freezing a large object from the root and
    // avoid unnecessary observation inside v-for fragments.
    var childOb = doNotObserve ? isObject(val) && val.__ob__ : observe(val);
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      get: function reactiveGetter() {
        var value = getter ? getter.call(obj) : val;
        if (Dep.target) {
          dep.depend();
          if (childOb) {
            childOb.dep.depend();
          }
          if (isArray(value)) {
            for (var e, i = 0, l = value.length; i < l; i++) {
              e = value[i];
              e && e.__ob__ && e.__ob__.dep.depend();
            }
          }
        }
        return value;
      },
      set: function reactiveSetter(newVal) {
        var value = getter ? getter.call(obj) : val;
        if (newVal === value) {
          return;
        }
        if (setter) {
          setter.call(obj, newVal);
        } else {
          val = newVal;
        }
        childOb = doNotObserve ? isObject(newVal) && newVal.__ob__ : observe(newVal);
        dep.notify();
      }
    });
  }

 2.MutationObserver函數,HTML5新特性之Mutation Observerasync

Mutation Observer(變更觀察器)是監視DOM變更的接口。當DOM對象樹發生任何變更時,Mutation Observer會獲得通知。ide

要概念上,它很接近事件。能夠理解爲,當DOM發生變更會觸發Mutation Observer事件。可是,它與事件有一個本質不一樣:事件是同步觸發,也就是說DOM發生變更馬上會觸發相應的事件;Mutation Observer則是異步觸發,DOM發生變更之後,並不會立刻觸發,而是要等到當前全部DOM操做都結束後才觸發。

這樣設計是爲了應付DOM變更頻繁的狀況。舉例來講,若是在文檔中連續插入1000個段落(p元素),會連續觸發1000個插入事件,執行每一個事件的回調函數,這極可能形成瀏覽器的卡頓;而Mutation Observer徹底不一樣,只在1000個段落都插入結束後纔會觸發,並且只觸發一次。

Mutation Observer有如下特色:

  • 它等待全部腳本任務完成後,纔會運行,即採用異步方式
  • 它把DOM變更記錄封裝成一個數組進行處理,而不是一條條地個別處理DOM變更。
  • 它便可以觀察發生在DOM節點的全部變更,也能夠觀察某一類變更
/**
   * Defer a task to execute it asynchronously. Ideally this
   * should be executed as a microtask, so we leverage
   * MutationObserver if it's available, and fallback to
   * setTimeout(0).
   *
   * @param {Function} cb
   * @param {Object} ctx
   */

  var nextTick = (function () {
    var callbacks = [];
    var pending = false;
    var timerFunc;
    function nextTickHandler() {
      pending = false;
      var copies = callbacks.slice(0);
      callbacks = [];
      for (var i = 0; i < copies.length; i++) {
        copies[i]();
      }
    }

    /* istanbul ignore if */
    if (typeof MutationObserver !== 'undefined') {
      var counter = 1;
      var observer = new MutationObserver(nextTickHandler);
      var textNode = document.createTextNode(counter);
      observer.observe(textNode, {
        characterData: true
      });
      timerFunc = function () {
        counter = (counter + 1) % 2;
        textNode.data = counter;
      };
    } else {
      // webpack attempts to inject a shim for setImmediate
      // if it is used as a global, so we have to work around that to
      // avoid bundling unnecessary code.
      var context = inBrowser ? window : typeof global !== 'undefined' ? global : {};
      timerFunc = context.setImmediate || setTimeout;
    }
    return function (cb, ctx) {
      var func = ctx ? function () {
        cb.call(ctx);
      } : cb;
      callbacks.push(func);
      if (pending) return;
      pending = true;
      timerFunc(nextTickHandler, 0);
    };
  })();

異步更新隊列,Vue.js 默認異步更新 DOM。每當觀察到數據變化時,Vue 就開始一個隊列,將同一事件循環內全部的數據變化緩存起來。若是一個 watcher 被屢次觸發,只會推入一次到隊列中。等到下一次事件循環,Vue 將清空隊列,只進行必要的 DOM 更新。在內部異步隊列優先使用MutationObserver,若是不支持則使用 setTimeout(fn, 0)。經過MutationObserver, 實現了異步更新隊列

相關文章
相關標籤/搜索