<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 深入響應式原理 大部分的基礎內容我們已經講到了,現在講點底層內容。Vue.js 最顯著的一個功能是響應系統 —— 模型只是普通對象,修改它則更新視圖。這讓狀態管理非常簡單且直觀,不過理解它的原理也很重要,可以避免一些常見問題。下面我們開始深挖 Vue.js 響應系統的底層細節。 ## 如何追蹤變化 把一個普通對象傳給 Vue 實例作為它的 `data` 選項,Vue.js 將遍歷它的屬性,用 [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) 將它們轉為 getter/setter。這是 ES5 特性,不能打補丁實現,這便是為什么 Vue.js 不支持 IE8 及更低版本。 用戶看不到 getter/setters,但是在內部它們讓 Vue.js 追蹤依賴,在屬性被訪問和修改時通知變化。一個問題是在瀏覽器控制臺打印數據對象時 getter/setter 的格式化不同,使用 `vm.$log()` 實例方法可以得到更友好的輸出。 模板中每個指令/數據綁定都有一個對應的 **watcher** 對象,在計算過程中它把屬性記錄為依賴。之后當依賴的 setter 被調用時,會觸發 watcher 重新計算 ,也就會導致它的關聯指令更新 DOM。 ![data](https://box.kancloud.cn/2016-01-03_5688e1a8be4be.png) ## 變化檢測問題 受 ES5 的限制,Vue.js **不能檢測到對象屬性的添加或刪除**。因為 Vue.js 在初始化實例時將屬性轉為 getter/setter,所以屬性必須在 `data` 對象上才能讓 Vue.js 轉換它,才能讓它是響應的。例如: ``` var data = { a: 1 } var vm = new Vue({ data: data }) // `vm.a` 和 `data.a` 現在是響應的 vm.b = 2 // `vm.b` 不是響應的 data.b = 2 // `data.b` 不是響應的 ``` 不過,有辦法在實例創建之后**添加屬性并且讓它是響應的**。 對于 Vue 實例,可以使用 `$set(key, value)` 實例方法: ``` vm.$set('b', 2) // `vm.b` 和 `data.b` 現在是響應的 ``` 對于普通數據對象,可以使用全局方法 `Vue.set(object, key, value)`: ``` Vue.set(data, 'c', 3) // `vm.c` 和 `data.c` 現在是響應的 ``` 有時你想向已有對象上添加一些屬性,例如使用 `Object.assign()` 或 `_.extend()` 添加屬性。但是,添加到對象上的新屬性不會觸發更新。這時可以創建一個新的對象,包含原對象的屬性和新的屬性: ``` // 不使用 `Object.assign(this.someObject, { a: 1, b: 2 })` this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 }) ``` 也有一些數組相關的問題,之前已經在[列表渲染](/guide/list.html#)中講過。 ## 初始化數據 盡管 Vue.js 提供了 API 動態地添加響應屬性,還是推薦在 `data` 對象上聲明所有的響應屬性。 不這么做: ``` var vm = new Vue({ template: '<div>{{msg}}</div>' }) // 然后添加 `msg` vm.$set('msg', 'Hello!') ``` 這么做: ``` var vm = new Vue({ data: { // 以一個空值聲明 `msg` msg: '' }, template: '<div>{{msg}}</div>' }) // 然后設置 `msg` vm.msg = 'Hello!' ``` 這么做有兩個原因: 1. `data` 對象就像組件狀態的模式(schema)。在它上面聲明所有的屬性讓組件代碼更易于理解。 2. 添加一個頂級響應屬性會強制所有的 watcher 重新計算,因為它之前不存在,沒有 watcher 追蹤它。這么做性能通常是可以接受的(特別是對比 Angular 的臟檢查),但是可以在初始化時避免。 ## 異步更新隊列 Vue.js 默認**異步**更新 DOM。每當觀察到數據變化時,Vue 就開始一個隊列,將同一事件循環內所有的數據變化緩存起來。如果一個 watcher 被多次觸發,只會推入一次到隊列中。等到下一次事件循環,Vue 將清空隊列,只進行必要的 DOM 更新。在內部異步隊列優先使用 `MutationObserver`,如果不支持則使用 `setTimeout(fn, 0)`。 例如,設置了 `vm.someData = 'new value'`,DOM 不會立即更新,而是在下一次事件循環清空隊列時更新。我們基本不用關心這個過程,但是如果想在 DOM 狀態更新后做點什么,這會有幫助。盡管 Vue.js 鼓勵開發者沿著數據驅動的思路,避免直接修改 DOM,但是有時確實要這么做。為了在數據變化之后等待 Vue.js 完成更新 DOM,可以在數據變化之后立即使用 `Vue.nextTick(callback)` 。回調在 DOM 更新完成后調用。例如: ``` <div id="example">{{msg}}</div> ``` ``` var vm = new Vue({ el: '#example', data: { msg: '123' } }) vm.msg = 'new message' // 修改數據 vm.$el.textContent === 'new message' // false Vue.nextTick(function () { vm.$el.textContent === 'new message' // true }) ``` `vm.$nextTick()` 這個實例方法比較方便,因為它不需要全局 `Vue`,它的回調的 `this` 自動綁定到當前 Vue 實例: ``` Vue.component('example', { template: '<span>{{msg}}</span>', data: function () { return { msg: 'not updated' } }, methods: { updateMessage: function () { this.msg = 'updated' console.log(this.$el.textContent) // => 'not updated' this.$nextTick(function () { console.log(this.$el.textContent) // => 'updated' }) } } }) ``` ## 計算屬性的秘密 應注意到 Vue.js 的計算屬性**不是**簡單的 getter。計算屬性持續追蹤它的響應依賴。在計算一個計算屬性時,Vue.js 更新它的依賴列表并緩存結果,只有當其中一個依賴發生了變化,緩存的結果才無效。因此,只要依賴不發生變化,訪問計算屬性會直接返回緩存的結果,而不是調用 getter。 為什么要緩存呢?假設我們有一個高耗計算屬性 `A`,它要遍歷一個巨型數組并做大量的計算。然后,可能有其它的計算屬性依賴 `A`。如果沒有緩存,我們將調用 `A` 的 getter 許多次,超過必要次數。 由于計算屬性被緩存了,在訪問它時 getter 不總是被調用。考慮下例: ``` var vm = new Vue({ data: { msg: 'hi' }, computed: { example: function () { return Date.now() + this.msg } } }) ``` 計算屬性 `example` 只有一個依賴:`vm.msg`。`Date.now()` **不是** 響應依賴,因為它跟 Vue 的數據觀察系統無關。因而,在訪問 `vm.example` 時將發現時間戳不變,除非 `vm.msg` 變了。 有時希望 getter 不改變原有的行為,每次訪問 `vm.example` 時都調用 getter。這時可以為指定的計算屬性關閉緩存: ``` computed: { example: { cache: false, get: function () { return Date.now() + this.msg } } } ``` 現在每次訪問 `vm.example` 時,時間戳都是新的。**但是,只是在 JavaScript 中訪問是這樣的;數據綁定仍是依賴驅動的。**如果在模塊中這樣綁定計算屬性 `{{example}}`,只有響應依賴發生變化時才更新 DOM。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看