Vue學習系列(一)——初識Vue.js核心

  • 2019 年 10 月 13 日
  • 筆記

 前言

    vue.js是一套構建用戶介面的漸進式框架,vue.js的目標是通過儘可能簡單的API實現響應的數據綁定和組合的視圖組件。

    vue通過DOM事件操作和指令來進行視圖層和模型層的相互通訊,會為每一處需要動態更新的DOM節點創建一個指令對象。每當一個指令對象觀測的數據變化時,它便會對所綁定的目標節點執行相應的DOM操作。基於指令的數據綁定使得具體的DOM操作都被合理地封裝在指令定義中,業務程式碼只需要涉及模板和對數據狀態的操作即可,這使得應用的開發效率和可維護性都大大提升。

    因此,數據綁定,組件是整個vue的核心。響應的數據綁定就是數據驅動視圖的概念。它讓你在寫 Web 應用介面時,只需要關注兩件事:數據如何展示和數據如何變化。一旦數據發生變化時,比如用戶輸入,或者 ajax 請求返回後數據發現修改,對應的視圖介面會自動的進行更新。

 原理

    vue.js是MVVM的架構,如圖:

 

    從圖中可以看出視圖層和模型層的相互傳遞,通過用戶操作來綁定一些DOM事件來重新渲染到視圖層。具體的內部架構如下圖:

 

 開始

一、 數據綁定

    實現方式:數據綁定即是視圖層和模型層的雙向綁定。即數據的改變驅動了視圖的自動更新。  

    通過ViewModel控制,修改數據,從而控制View的展示,實現MVVM的思想。

 

    裡面的兩個屬性getter和setter,在這兩個函數內部實現依賴的收集和觸發,而且完美支援嵌套的對象結構。對於數組,則通過包裹數組的可變方法(比如push)來監聽數組的變化。這使得操作Vue.js的數據和操作原生對象幾乎沒有差別。

  • Obejct.defineProperty 【提供getter 和 setter】
  • Observer 【提供getter 和 setter】—— 訂閱者模式,一個目標對象管理所有相依於它的觀察者對象,並且在它本身的狀態改變時主動發出通知,用來實時事件處理系統。
  • watcher 【提供getter 和 setter】 —— 模板和 Observer 對象結合在一起的紐帶
  • Dep 【負責收集watcher】
  • Directive 【處理Vue模板指令】

    observe -> 觸發setter -> watcher -> 觸發update -> Directive -> 觸發update -> 指令(如上圖流程所示)

<span>Hello, this is {{name}}</span>  <script>  var app = new Vue({      el : '#app',      data : {          name: 'i3yuan'      }  })    </script>

new Vue 執行時做了什麼

function Vue(option) {    var data = option.data    this.data = data    // 掛載 getter 和 setter    observe(data, this)    var id = option.el    // 編譯 模板    var dom = new Compile(document.querySelector(id), this)    // 把編譯好的模板掛載到 #app 上    document.querySelector(id).appendChild(dom)  }  //observe構造函數  function observe(obj, vm) {    Object.keys(obj).forEach(key => {      defineReactive(vm, key, obj[key])    })  }  //defineReactive  function defineReactive(vm, key, val) {    // 為每個變數分配一個 dep實例    var dep = new Dep()    // 配置getter和setter並且掛載到vm上    Object.defineProperty(vm, key, {      get() {        if ( Dep.target ) {          // JS的瀏覽器單執行緒特性, 保證整個全局變數在同一時間內, 只有一個監聽器使用          dep.addSub(Dep.target)        }        return val      },      set(newVal) {        if ( newVal == val ) return;        val = newVal;        // 作為發布者發出通知        dep.notify()      }    })  }    //Dep構造函數  function Dep() {    // 存放watcher    this.subs = []  }    Dep.prototype = {    // 添加watcher, 也就是添加訂閱    addSub(sub) {      this.subs.push(sub)    },    // 通知所有watcher    notify() {      this.subs.forEach(sub => {        sub.update()      })    }  }        function Compile(node, vm) {    if(node) {      this.$frag = this.nodeToFragment(node, vm)      return this.$frag    }  }    //watcher構造函數  function Watcher(vm, node, name, type) {    // 單例, 使用原因未知    Dep.target = this    // 姓名    this.name = name;    // 呵呵噠 uid    this.id = ++uid;    // 與變數相關的Node節點    this.node = node;    // vm 實例    this.vm = vm;    // 變數類型  nodeValue  || value    this.type = type;    // 觸發自己原型上的update方法    this.update()    // Watcher 實例創建結束就把單例置空    Dep.target = null  }      Watcher.prototype = {    update() {      this.get()      if(!batcher) {        // bastcher 單例        batcher = new Batcher()      }      // 加入隊列      batcher.push(this)    },    // 獲取新值掛到自己的實例上    get() {      this.value = this.vm[this.name]  // 觸發getter    }  }

 整個流程:

new Vue –> Observe 掛載 setter 和 getter –> Compile 編譯模板 –> 為每個指令分配一個watcher –> 創建時會調用一次watcher.update 將自己加入到batcher的隊列 –>
並且此時會觸發 getter 將watcher加入dep –> batcher 統一來處理watcher後初始化自己 –> 當用戶修改某個變數時 –> dep通知watcher –> watcher又被加入batcher處理 –> watcher 更新dom 

二、視圖組件:

    組件,相信大部分開發人員在開發現代框架的時候都或多或少的遇到一些組件,可想而知,現代框架已經走向了組件化的道路,雖然不同的主流框架都有不同封裝組件的方式,但是核心思想都差不多一樣。通過分離頁面,使得整個頁面由很多個組件構成,給我們的第一個印象就是,就像我們平時使用到的MVC中的分視圖,或者子視圖,但是又不一樣,雖然組件是一部分,但是卻是自己的一個整體,和其他組件相互獨立,高內聚低耦合,可以通過自定義標籤的形式來使用。

    因此,在開發中, 把整一個網頁的拆分成一個個區塊,每個區塊我們可以看作成一個組件。網頁由多個組件拼接或者嵌套組成:

// 定義一個名為 Mycomponent  的新組件  Vue.component('Mycomponent', {      // 模板      template: '<div>{{msg}} {{privateMsg}}</div>',      // 接受參數      props: {          msg: String      },      // 私有數據,需要在函數中返回以避免多個實例共享一個對象      data: function () {          return {              privateMsg: 'component!'            }      }  })
<Mycomponent msg="i3yuan"></Mycomponent>

組件的核心選項:

1 模板(template):模板聲明了數據和最終展現給用戶的DOM之間的映射關係。

2 初始數據(data):一個組件的初始數據狀態。對於可復用的組件來說,這通常是私有的狀態。

3 接受的外部參數(props):組件之間通過參數來進行數據的傳遞和共享。

4 方法(methods):對數據的改動操作一般都在組件的方法內進行。

5 生命周期鉤子函數(lifecycle hooks):一個組件會觸發多個生命周期鉤子函數,最新2.0版本對於生命周期函數名稱改動很大。

6 私有資源(assets):Vue.js當中將用戶自定義的指令、過濾器、組件等統稱為資源。一個組件可以聲明自己的私有資源。私有資源只有該組件和它的子組件可以調用。

注意事項

  • 組件註冊一定要在實例化Vue對象之前,否則會報錯
  • 屬性名為components,s千萬別忘了
  • 不管是全局組件還是局部組件,data都必須是一個函數,且return不能換行
  • 因為this指向的問題,建議用es5的方式寫方法

 總結

1.通過官方文檔的學習和總結,認識到了vue的框架和通訊方式,以視圖組件和數據綁定為核心構建完整的漸進式的框架。

2.從上述的兩大核心的描述,我們大體理解了Vue的構建方式,通過基本的指令控制DOM,實現提高應用開發效率和可維護性。

3.下一節我們將對Vue視圖組件的核心概念進行詳細說明。