最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue實(shí)現(xiàn)雙向綁定和依賴收集遇到的坑

 更新時(shí)間:2018年11月29日 08:03:31   作者:毛毛開飛機(jī)  
這篇文章主要介紹了vue的雙向綁定和依賴收集,主要是通過Object.defineProperty() 實(shí)現(xiàn)雙向綁定,具體思路代碼大家跟隨小編一起看看吧

在掘金上買了一個(gè)關(guān)于解讀vue源碼的小冊,因?yàn)槭歉顿M(fèi)的,所以還比較放心

在小冊里看到了關(guān)于vue雙向綁定和依賴收集的部分,總感覺有些怪怪的,然后就自己跟著敲了一遍。 敲完后,發(fā)現(xiàn)完全無法運(yùn)行,  坑啊,  寫書人完全沒有測試過。

然后自己完善代碼, 越寫越發(fā)現(xiàn)坑, 問題有些大。。。。。。

最后自己重新實(shí)現(xiàn)了一遍,代碼較多。 用到觀察訂閱者模式實(shí)現(xiàn)依賴收集, Object.defineProperty() 實(shí)現(xiàn)雙向綁定

/*
  自己寫的代碼, 實(shí)現(xiàn)vue的雙向綁定和依賴收集
  場景: 多個(gè)子組件用到父組件data中的數(shù)據(jù), 當(dāng)父組件data中的此數(shù)據(jù)發(fā)生改變時(shí), 
  所有依賴它的 子組件全部更新
  通常子組件的從父組件中拿取的數(shù)據(jù)不允許發(fā)生改變
*/
  //訂閱者 Dep
  //一個(gè)訂閱者只管理一個(gè)數(shù)據(jù)
  class Dep {
    constructor () {
      this.subs = []  //存放vue組件
    }
    addSubs (sub) {
      this.subs.push(sub)
      console.log('add watcher: ', sub._name)
    }
    notify () {
      this.subs.forEach( sub => {  //通知vue組件更新
        sub.update()
      })
    }
  }
  //監(jiān)聽者
  //一個(gè)vue實(shí)例包含一個(gè)Watcher實(shí)例
  class Watcher {
    // 在實(shí)例化Watcher時(shí), 將Dep的target指向此實(shí)例, 在依賴收集中使用
    // 因?yàn)橐蕾囀占窃诮M件初始化時(shí)觸發(fā)的, 而數(shù)據(jù)變更后視圖相應(yīng)變更是在初始化后
    // 所以讓Dep.target指向此實(shí)例, 當(dāng)此vue實(shí)例初始化完成后, 再指向下一個(gè)正在初始化的vue實(shí)例完成依賴收集
    constructor (name) {
      Dep.target = this
      this._name = name
    }
    update () {
      // 這里模擬視圖更新
      // 其實(shí)還應(yīng)該讓子組件的props相應(yīng)值與父組件更新的數(shù)據(jù)同步
      console.log("子組件視圖更新了..." + this._name)
    }
  }
  //對data中的數(shù)據(jù)設(shè)置讀寫監(jiān)聽, 并且創(chuàng)建訂閱者, 用于收集子組件的依賴和發(fā)布
  function defineReactive (obj, key, value) {
    // 對vue實(shí)例中data對象的每一個(gè)屬性都 設(shè)置一個(gè)訂閱者Dep
    let dep = new Dep()
    // 第二個(gè)vue實(shí)例的監(jiān)聽 覆蓋了第一個(gè)vue實(shí)例的監(jiān)聽, 因?yàn)橐玫膐bj是同一個(gè)
    Object.defineProperty(obj, key, {
      configurable: true,
      enumerable: true,
      get () {  
      // 在讀此屬性時(shí), 將當(dāng)前 watcher 對象收集到此屬性的 dep 對象中
      // 在實(shí)例化vue時(shí)將Dep.target指向當(dāng)前Watcher
      // get()依賴收集的時(shí)候是vue組件初始化的時(shí)候, set()是在初始化后
        if (dep.subs.indexOf(Dep.target) === -1) {
          dep.addSubs(Dep.target)
        }
        //return obj[key]   此寫法報(bào)錯(cuò) 提示棧溢出 原因是無限調(diào)用get()
        return value
      },
      set (newVal) {  // 此屬性改變時(shí), 通知所有視圖更新
        if (newVal !== value) {
          value = newVal
          dep.notify()  
        }
      }
    })
  }
  //接收一個(gè)對象作為參數(shù), 將該對象的所有屬性調(diào)用defineReactive設(shè)置讀寫監(jiān)聽
  function observer (obj) {
    if (!obj || (typeof obj !== 'object')) {
      return 
    }
    Object.keys(obj).forEach( key => {
      defineReactive(obj, key, obj[key])
    }) 
  }
  // 構(gòu)造函數(shù), 監(jiān)聽 配置options中的data()方法返回的對象的所有屬性 的讀寫
  class Vue {
    constructor (options) {
      this._name = options.name
      this._data = options.data
      // 每個(gè)vue組件都是一個(gè)vue實(shí)例, 在一個(gè)頁面中有多個(gè)vue實(shí)例
      // 在初始化該vue實(shí)例時(shí), new一個(gè)Watcher對象, 使Dep.target指向此實(shí)例
      new Watcher(options.name)
      // 給data中的數(shù)據(jù)掛載讀寫監(jiān)聽
      observer(this._data)
      //模擬vue解析template過程, 獲取從父組件傳遞過來的props
      //在這里進(jìn)行依賴收集
      this._props = options.props ? getProps() : {}
      // 實(shí)例化該組件的子組件
      this._children = options.render ? (options.render() || {}) : {}
    }
  }
  // 父組件數(shù)據(jù)
  let data = {
    first: "hello",
    second: 'world',
    third: ['啦啦啦']
  }
  let times = 0
  // 第一次調(diào)用返回的是第一個(gè)子組件的從父組件繼承的數(shù)據(jù)(vue中props屬性的值)
  // 第二次調(diào)用返回的是第二個(gè)子組件的從父組件繼承的數(shù)據(jù)(vue中props屬性的值)
  function getProps () {
    times++
    if (times == 1) {
      let obj = {first: "", second: ""}
      Object.keys(obj).forEach( key => {
        // 如果是對象, 則進(jìn)行深拷貝
        // 這里使用到了父組件的數(shù)據(jù), 觸發(fā)依賴收集
        if (data[key] instanceof Object) {
          obj[key] = JSON.parse(JSON.stringify(data[key]))
        } else {
          obj[key] = data[key]
        } 
      })
      return obj
    } else if (times == 2) {
      let obj = {first: "", third: ""}
      Object.keys(obj).forEach( key => {
        if (data[key] instanceof Object) {
          obj[key] = JSON.parse(JSON.stringify(data[key]))
        } else {
          obj[key] = data[key]
        } 
      })
      return obj
    }  
  }
   let vue_root = new Vue({
     name: 'vue_root',
     data,
     //模擬編譯template和實(shí)例化vue的過程 
     //在編譯父組件 并且傳遞參數(shù)給子組件時(shí), 將子組件的 watcher 添加進(jìn)父組件的 dep
     render () {
       let vue_1 = new Vue({
         name: 'vue_1',
         data: {},
         props: true,
         render () {}
       }) 
       let vue_2 = new Vue({
         name: 'vue_2',
         data: {},
         props: true,
         render () {}
       }) 
       return {
         vue_1,
         vue_2
       }
     }
   })
  console.log(vue_root)
   vue_root._data.first = 'hello hello'  // vue_1 和 Vue_2 都依賴此數(shù)據(jù), 都更新
   vue_root._data.third = "aaa"      // 只有 vue_2 依賴到了此數(shù)據(jù), 更新

總結(jié)

以上所述是小編給大家介紹的vue的雙向綁定和依賴收集遇到的坑,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • 詳細(xì)對比Ember.js和Vue.js

    詳細(xì)對比Ember.js和Vue.js

    這篇文章主要介紹了詳細(xì)對比Ember.js和Vue.js,對JS框架感興趣的同學(xué),可以參考下
    2021-05-05
  • vue引入組件的幾種方法匯總

    vue引入組件的幾種方法匯總

    這篇文章主要介紹了vue引入組件的幾種方法匯總,包括常用的局部引入,這里需要注意在哪個(gè)頁面需要就在那個(gè)頁面引入、注冊、使用,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-10-10
  • vue攔截器及請求封裝代碼

    vue攔截器及請求封裝代碼

    這篇文章主要介紹了vue攔截器及請求封裝代碼,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • vue中使用@change的方法

    vue中使用@change的方法

    @change 是 Vue.js 中用于監(jiān)聽表單元素值變化的事件處理器,很多組件有@change事件,那到底如何獲取到當(dāng)前的參數(shù)呢?本文給大家詳細(xì)講解,感興趣的朋友一起看看吧
    2023-11-11
  • Vue混入mixins分發(fā)組件可復(fù)用功能

    Vue混入mixins分發(fā)組件可復(fù)用功能

    混入 (mixin) 提供了一種非常靈活的方式,來分發(fā) Vue 組件中的可復(fù)用功能。一個(gè)混入對象可以包含任意組件選項(xiàng)。當(dāng)組件使用混入對象時(shí),所有混入對象的選項(xiàng)將被“混合”進(jìn)入該組件本身的選項(xiàng)
    2022-09-09
  • 基于vue.js實(shí)現(xiàn)側(cè)邊菜單欄

    基于vue.js實(shí)現(xiàn)側(cè)邊菜單欄

    這篇文章主要為大家詳細(xì)介紹了基于vue.js實(shí)現(xiàn)側(cè)邊菜單欄的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • vue中的任務(wù)隊(duì)列和異步更新策略(任務(wù)隊(duì)列,微任務(wù),宏任務(wù))

    vue中的任務(wù)隊(duì)列和異步更新策略(任務(wù)隊(duì)列,微任務(wù),宏任務(wù))

    這篇文章主要介紹了vue中的任務(wù)隊(duì)列和異步更新策略(任務(wù)隊(duì)列,微任務(wù),宏任務(wù)),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 通過vue-cli3構(gòu)建一個(gè)SSR應(yīng)用程序的方法

    通過vue-cli3構(gòu)建一個(gè)SSR應(yīng)用程序的方法

    這篇文章主要介紹了通過vue-cli3構(gòu)建一個(gè)SSR應(yīng)用程序,以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
    2018-09-09
  • vue2.0中組件傳值的幾種方式總結(jié)

    vue2.0中組件傳值的幾種方式總結(jié)

    這篇文章主要介紹了vue2.0中組件傳值的幾種方式總結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Vue2.x通用條件搜索組件的封裝及應(yīng)用詳解

    Vue2.x通用條件搜索組件的封裝及應(yīng)用詳解

    這篇文章主要為大家詳細(xì)介紹了Vue2.x通用條件搜索組件的封裝及應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05

最新評論

常宁市| 沾化县| 白城市| 杭锦旗| 红河县| 亳州市| 开江县| 通海县| 黎川县| 平遥县| 遂平县| 宜章县| 任丘市| 富源县| 吕梁市| 长兴县| 吉木乃县| 北票市| 乳山市| 凤冈县| 霍城县| 东海县| 耿马| 拉萨市| 舟曲县| 民勤县| 故城县| 英吉沙县| 广东省| 拜泉县| 包头市| 哈密市| 云安县| 东港市| 上林县| 苏州市| 汝城县| 麦盖提县| 茂名市| 清徐县| 章丘市|