<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國際加速解決方案。 廣告
                >[success] # 了解 -- 響應式工作原理(二) ~~~ 1.這次從代碼運行角度來看這個問題 2.在使用vue 時候,'數據模型僅僅是普通的 JavaScript 對象。而當你修改它們時,視圖會進行更新', 從而形成我們常說的數據操作視圖的效果 ~~~ >[info] ## 如何實現這種效果 ~~~ 1.下面的說明案例引用了,vue官方文檔中推薦的教學視頻里面的內容 ~~~ [在 Vue Mastery 觀看視頻講解](https://www.vuemastery.com/courses/advanced-components/build-a-reactivity-system "Vue Reactivity") >[danger] ##### 先看一個vue 的例子 ~~~ 1.在頁面中調用的'addPrice' 方法,頁面會重新計算相乘的表達式price * quantity,然后更新頁面 ~~~ ~~~ <div id="app"> <div>Price: ${{ price * this.quantity }}</div> <div>Taxes: ${{ totalPriceWithTax }}</div> <button @click='addPrice'>點擊</button> </div> <script> var vm = new Vue({ el: '#app', data: { price: 5.00, quantity: 2 }, }, methods:{ addPrice(){ this.price++ } } }) </scprit> ~~~ >[danger] ##### 將上面的代碼用js 通常編程工作方式表示 ~~~ 1.下面正常的js邏輯代碼是否能像vue一樣,當price 發生改變期待著total 也可以重新計算,但實際結果卻是 打印出來的結果為10 而不是12 2.JavaScript是程序性的,不是反應性的,為了使total反應性,我們必須使用JavaScript使事物表現不同 ~~~ ~~~ let price = 5 let quantity = 2 let total = price * quantity price++ console.log(`total is ${total}`) // 10 ~~~ >[danger] ##### 如何做到響應式 ~~~ 1.如果可以讓上面的代碼total 可以在每次price 發生變化后接著調用,就可以實現響應式的效果列如: let price = 5 let quantity = 2 let total = price * quantity price++ total = price * quantity console.log(`total is ${total}`) // 12 2.雖然實現了我們想要的但是過于簡陋,現在進行優化,我們的思路是需要有一個可以記錄行為的地方 也就是' price * quantity '這個操作,在數據發生變化的時候需要一個方法重新調用我們記錄的這個行為 let price = 5 let quantity = 2 let total = 0 let target = null let storage = [] // 來記錄需要執行的行為動作,暫時保存起來 function record() { storage.push(target) } // 當數據變化的時候執行在record記錄的要執行的相應動作 function replay() { storage.forEach(run => run()) } target = () => { total = price * quantity } // 負責記錄price * quantity 這個行為 record() target() console.log(`total is ${total}`) // 10 price++ // 數據改變調用記錄的行為 replay() console.log(`total is ${total}`) // 12 ~~~ >[danger] ##### 通過觀察者模式 來有優化上面的代碼 ~~~ 1.發布者?--?發布者要收集所有觀察者才能?給每個觀察者發送要接受的內容 2.觀察者 -- 等待發布者發送指令 3.也就是說發布者收集所有需要被觀察的內容,當發布者到達某個觸發條件時候,會依次觸發記錄下來的 觀察者,發布者更像一個開關負責收集所有需要被在特定時間要出觸發的觀察者 ~~~ * 最初的構想代碼 ~~~ 1.下面的問題 就是純靠控制 dep 做到發布 和 訂閱,其實是可以的沒問題的解決思路,如果你看過這個章節 的第一篇你就會知道利用'Object.defineProperty' 給屬性的'get' 和 'set' 屬性進行一次注冊綁定,綁定后 我們想通過外部因素影響內部,先記住這個想法 ~~~ ~~~ // 觀察者 和 發布訂閱 共同性質 改變通知 可以一對多 class Dep { constructor() { this.sub = []; } // 記錄 行為 listen(fn) { if (typeof fn === 'function') this.sub.push(fn); } // 調用行為 trigger(...args) { return this.sub.length > 0 && this.sub.forEach((fn) => fn(...args)); } } const watcher = { total: 0, price: 1, num: 1, }; const dep = new Dep(); dep.listen(() => { watcher.total = watcher.price * watcher.num; }); dep.trigger(); console.log(watcher.total); watcher.price++; dep.trigger(); console.log(watcher.total); ~~~ * 改進一下抽離觀察者 ~~~ // 發布者 -- 主要是用來收集,和統一執行被收集來的訂閱者 class Dep { constructor() { this.subscribers = [] // 收集訂閱者 } depend() { // 收集訂閱者方法 if (target && !this.subscribers.includes(target)) { this.subscribers.push(target) } } notify() { // 負責統一執行這些訂閱者 this.subscribers.forEach(sub => sub()) } } // 訂閱 function watcher(myFunc) { target = myFunc // 在接受到調用者指令時候執行的回調函數 dep.depend() target() // 上來先調用一次 target = null } const dep = new Dep() let price = 5 let quantity = 2 let total = 0 watcher(() => { total = price * quantity }) console.log(`total is ${total}`) // 10 price++ dep.notify() console.log(`total is ${total}`) // 12 ~~~ >[info] ## 新的問題 合適觸發發布者 ~~~ 1.剛才都是通過代碼邏輯進行邏輯步驟調用,想讓數據更加靈活不用每次都手動調用,vue2.0采用了 'Object.defineProperty'這是一個函數,'它允許我們為屬性定義getter和setter函數' ~~~ >[danger] ##### Object.definePropert [關于 Object.definePropert 可以看我另外一篇文章 ](http://www.hmoore.net/cyyspring/more/1246692) ~~~ 1.通過下面的小例子可以發現,現在已經可以對數據變化進行監控了,這樣就可以做到對應觸發'發布者', ~~~ ~~~ let person = { name: 'w', } Object.defineProperty(person, 'name', { get() { console.log('調用時候執行') }, set(val) { console.log('賦值時候執行') } }) person.name // 執行get person.name = 'y' // 這里執行set ~~~ >[danger] ##### 將上面的案例進行結合 ~~~ 1.這里做個說明Object.defineProperty 對屬性進行get 和 set 是時候,在沒有調用情況僅僅只是一個綁定。 2.僅僅是綁定因此'watcher' 先觸發有了統一的target 3.這個案例就說明了抽離觀察這和訂閱者的好處 可以通過外部去控制 ~~~ ~~~html <!DOCTYPE html> <html lang="en" style="height: 100%;"> <body style="height: 100%;"> <div id="app">hello</div> <div id="app1">hello</div> <button id="changeViwe">觸發視圖更新 </button> <button id="changeViwe1">觸發視圖更新1 </button> </body> <script> /** * 描述 響應代理 * @param {Object} vm 代理后的對象 * @param {Object} data 被代理的對象 * @returns {any} */ function proxy(vm,data){ Object.keys(data).forEach(key => { // 注冊觀察者 const dep = new Dep() Object.defineProperty(vm,key,{ enumerable:true, configurable:true, get(){ console.log(1234); // 在get 時候記錄這個訂閱 // Object.defineProperty 在第一次注冊的時候是不會執行get的 // 因此其實第一遍給每個屬性綁定上get 和set時候只是注冊了 dep 觀察者對象,并沒有執行內部get 和set 方法 // 所以也就并沒有往里面填入實際的觀察方法 dep.depend() return data[key]; }, set(val){ console.log(1234); if(val===data[key]) return; data[key] = val; // 原來簡易版本的執行是寫死的只能固定某個位置渲染 // document.getElementById('app').textContent = Object.values(data).join() // 現在利用觀察者模型在dep.depend() 去注冊了 外部希望執行的回調函數代碼,代碼靈活 dep.notify() // 在賦值時候觸發訂閱動作 }, }) }) } /** * 描述 發布者 -- 主要是用來收集,和統一執行被收集來的訂閱者 */ class Dep{ constructor(){ this.subs = [] } // 這里有點區別之前的做的觀察者模型,那時候是有個函數參數 // 這個函數參數通過調用depend 注冊 // 但是現在觸發他的方法被在Object.defineProperty get 提前聲明 // 你在最初的時候不知道數據會根據什么數據動態變化 // 因此需要更為動態的形式去傳遞 方法 depend(){ if(target && !this.subs.includes(target)){ this.subs.push(target) } } // 去調用 notify(msg){ const { length } = this.subs length && this.subs.forEach(fun=>fun()) } } /** * 描述 訂閱者 * @param {Function} fun 執行的訂閱回調函數 */ function watcher(fun){ target = fun // 最開始的進階案例我們在 wather 這個函數調用了 Dep 中depend 來進行觀察的注冊 // 現在 因為通過Object.defineProperty 做了響應模型,這樣get 時候就能夠自動 // 幫助我們注冊了 Dep 中depend 來進行觀察 // 因此只用當fun 這個回調方法中使用了Object.defineProperty 包裹的屬性才會觸發 // 其實就是為解決在get 方法中自動添加監聽回調觸發 fun() target = null } const data = {msg:"123",age:123} const vm = {} proxy(vm,data) /** * 描述 id為app 的dom 節點插入內容 */ function appendAppRoot(){ document.getElementById('app').textContent = vm.msg + vm.age } /** * 描述 id為app1 的dom 節點插入內容 */ function appendApp1Root(){ document.getElementById('app1').textContent = vm.msg + vm.age } watcher( // 更加動態的在外部執行訂閱的方法 // watcher 內部會自調用 回調函數,回調函數中 vm.msg + vm.age 這兩段就會觸發get // 形成訂閱 appendAppRoot ) document.getElementById('changeViwe').onclick = function(){ // 當賦值的時候觸發set ,set 會觸發在調用watcher 時候注冊進入觀者某型中subs里面的回調 vm.msg = "測試" } watcher( // 更加動態的在外部執行訂閱的方法 appendApp1Root ) document.getElementById('changeViwe1').onclick = function(){ vm.msg = "測試666" } </script> </html> ~~~
                  <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>

                              哎呀哎呀视频在线观看