<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] **** ## 1 Vue的數據綁定 >[info] 數據綁定的實現分為**數據層劫持**與**UI層事件注冊**。 >[info] 這里分析vue對數據層劫持的實現機制 ## 2 實現observer(數據觀察者) >[info] 對observe對象的屬性進程set/get操作劫持 >[info] 實現劫持后對Observer對象屬性的set與get操作可以觸發響應操作, >[info] 其中的操作包括UI層的更新與其他數據的刷新 ~~~ export default class Observer{ constructor(value){ ;屬性value獲取 this.value = value ;屬性遍歷 this.walk(value) } ;遍歷操作 walk(value){ ;獲取屬性value的keys var keys = Object.keys(value) ;遍歷keys keys.foreach( ;將key對應的值轉換為劫持屬性 key=>this.convert(key,value[key]) ) } ;轉換屬性為劫持屬性 convert(key,val){ defineReactive(this.value,key,val) } ;屬性轉換操作 expot function defineReactive(obj,key,val){ ;val遞歸遍歷 var childOb = observe(val) ;注冊為劫持屬性 Object.defineProperty(obj,key,val){ enumerable : true, configurable : true, get:() => val, set:newVal=>{ childOb = observe(newVal) } } } ;屬性遞歸操作 export function observe(value,vm){ if(!value||typeof value ! = 'object'){ return } ;生成數據監視器observer return new Observer(value) } } ~~~ ## 3 實現Dep(消息訂閱器) >[info] set操作會廣播消息到訂閱器數組的所有訂閱者 >[info] 消息訂閱器數組的訂閱者將會進行刷新操作。 >[info] 消息訂閱器中的訂閱者可以是UI層也可以是數據層 ~~~ ;Dep實現 export default class Dep{ constructor(){ this.subs = [] } addSub(sub){ this.subs.push(sub) } notify(){ this.subs.forEach(sub=>sub.update()) } } ~~~ ~~~ ;注冊Dep(消息訂閱器)到observer(數據觀察者) export function defineReactive(obj,key,val){ ;創建訂閱器數組 var dep = new Dep() ;注冊為劫持屬性 var childOb = observe(val) Object.defineProperty(obj,key,{ enumberable:true, configurable:true, get:()=>val, set:newVal =>{ ;舊值 var value = val ;比較新舊值 if(newVal === value){ return } ;值不相等進行處理 val = newVal childOb = observe(newVal) ;廣播數據更新到消息訂閱者數組 dep.notify() } }) } ~~~ ## 4 實現Watcher(消息訂閱者) >[info] 消息訂閱者存儲在消息訂閱器數組中 >[info] 數據層的set操作會廣播消息到訂閱器數組 >[info] 訂閱器數組中的訂閱者會進行自我刷新操作 >[info] 消息訂閱者可以是數據層也可以是UI層 ~~~ ;實現消息訂閱者 export default class Watcher{ constructor(vm,expOrFn,cb){ this.cb = cb this.vm = vm this.expOrFn = expOrFn this.value = this.get() } ;消息訂閱者刷新操作 update(){ this.run() } ;刷新運行過程 run(){ const value = this.get() if( vakue ! == this.value){ this.value = value this.cb.call(this.vm) } } ;獲取指令表達式的值 get(){ const value = this.vm._data[this.expOrFn] return value } } ~~~ >[info] 現在需要將消息訂閱者注冊到消息訂閱器中 >[info] 這樣數據層set層廣播消息到消息訂閱器數組 >[info] 消息訂閱者可接受消息進行相應刷新操作 >[info] 注冊的關鍵在Object.defineProperty的get()被調用時 >[info] Watcher的get()會調用數據層的get()。 >[info] 觸發get劫持,注冊Watcher到Dep數組中 >[info] 為了判斷是否在Watcher中進行get,需要設置一個狀態位 ~~~ ;修改后的watcher export default class Watcher{ .... get(){ ;設置狀態標志 Dep.target = this ;調用Object.defineProperty()注冊的get劫持 const value = this.vm._data[this.expOrFn] ;還原狀態標識 Dep.target = null return value } .... } ~~~ ~~~ ;修改后的definReactive() export function defineReactive(obj,key,val){ ;創建消息訂閱器數組 var dep = new Dep() ;修改為劫持屬性 var childOb = observe(val) Object.defineProperty(obj,key,{ enumberable : true, configurable : true, get:() => { ;檢查是否watch的get,注冊到Dep中 if(Dep.target){ dep.addSub(Dep.target) } return val }, set:newVal => { var value = val ;值相等直接返回 if(newVal === value){ return } ;值不相等觸發刷新操作 val = newVal childOb = observe(newVal) dep.ontify() } }) } ~~~ ## 5 總結 >[info] 數據綁定實現了對數據層set與get的劫持與刷新操作關聯 >[info]Observer實現對數據屬性的set/get的劫持 >[info]Dep實現對set操作的消息廣播數組的管理 >[info]Watcher對應特定消息的訂閱者,可以實現為數據層刷新或者UI層刷新 ## 6 參考 [vue的數據綁定實現](https://segmentfault.com/a/1190000004384515)
                  <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>

                              哎呀哎呀视频在线观看