中文字幕第五页-中文字幕第页-中文字幕韩国-中文字幕最新-国产尤物二区三区在线观看-国产尤物福利视频一区二区

vue雙向數據綁定的實現學習之監聽器的實現方法

提到了vue實現的基本實現原理:Object.defineProperty() -數據劫持 和 發布訂閱者模式(觀察者),下面講的就是數據劫持在代碼中的具體實現。

樂平網站制作公司哪家好,找創新互聯!從網頁設計、網站建設、微信開發、APP開發、響應式網站等網站項目制作,到程序開發,運營維護。創新互聯2013年開創至今到現在10年的時間,我們擁有了豐富的建站經驗和運維經驗,來保證我們的工作的順利進行。專注于網站建設就選創新互聯。

1.先看如何調用vue 雙向數據綁定的實現學習之監聽器的實現方法

new一個對象,傳入我們的參數,這個Myvue ,做了啥?

vue 雙向數據綁定的實現學習之監聽器的實現方法

上面看到了在實例化一個Myvue 對象的時候,會執行init方法, init 方法做了兩個事,調用了observer 方法,和 實例化調用了 compile 方法。 到這里我們就明白了,實例化一個Myvue后,我們要做的就是監聽數據變化和編譯模板 。

上面Object.key() 方法,實例化時傳入的data里面對應的變量緩存到 Myvue 對象的 $prop上,這樣方便在后續處理數據。怎么個方便法呢!...

2.observer 的實現

observer ,模式里面的角色定位 他是一個發布者,也可以理解為是一個觀察者

function observer (data) {
  if(!data || typeof data !== 'object') {
    return;
  }
  Object.keys(data).forEach(key => {
    // 對每個屬性監聽處理
    defineReactive(data, key, data[key]);
  })
}

defineReactive

function defineReactive (data,key,value) {
  // 每次訪問/修改屬性的時候 實例化一個調度中心Dep
  var dep = new Dep();
  Object.defineProperty(data,key,{
    get: function() {
      // 添加到watcher 的Dep 調度中心
      if (Dep.target) { // Dep.target 是個什么鬼? 轉到watcher.js 它是某個訂閱者 watcher
        dep.addSub(Dep.target); //這個代碼段的意思: 如果有訂閱者(訪問/修改屬性的時候) 就將這個訂閱者統一放進 Dep 調度中心中
      }
      // console.log(`${key}屬性被訪問了`)
      return value
    },
    set: function (newValue) {
      if (value != newValue) {
        // console.log(`${key}屬性被重置了`)
        value = newValue
        dep.notify(); //我這里有做改動了,通知調度中心的notify方法
      }
    }
  })
  // 遞歸調用,observe 這個value
  observer(value)
}

Dep: 這里是所有訂閱者的一個調度中心,它不是直接監聽 發布者的信息,發布者將要發布的信息 發布到 一個中介、調度中心(Dep),由這個Dep 來調度信息給哪個訂閱者(Watcher)

// 統一管理watcher訂閱者的Dep (調度中心) Dispatch center
function Dep () {
  // 所有的watcher 放進這里統一管理
  this.subs = []
}
Dep.target = null;
// 通知視圖更新dom的 notify的方法
Dep.prototype.notify  = function () {
  // this.subs 是上面訂閱器watcher 的集合
  this.subs.forEach(sub => {
    // sub 是某個Watcher 具體調用某個Watcher的update 方法
    sub.update()
  })
}
// 添加訂閱者的方法
Dep.prototype.addSub = function (sub) {
  this.subs.push(sub)
}

3.訂閱器Watcher

// 具體的訂閱器Watcher
// 傳入一個vue 的實例, 監聽的屬性, 以及處理的回調函數
function Watcher (vm,prop,callback) {
  this.vm = vm;
  this.$prop = prop;
  this.value = this.get();
  this.callback = callback; // 具體watcher所具有的方法,不同的watcher 不同的回調函數,處理不同的業務邏輯
 }
// 添加watcher 獲得屬性的get 方法,當有屬性訪問/設置 的時候,就產生訂閱者 將這個訂閱者放進調度中心
Watcher.prototype.get = function () {
  Dep.target = this;
  // 獲得屬性值
  const value = this.vm.$data[this.$prop];
  return value
}
// 添加watcher的更新視圖的方法
Watcher.prototype.update = function () {
  // 當屬性值有變化的時候,執行方法,更新試圖
  const value = this.vm.$data[this.$prop];
  const oldValue = this.value;
  // update 執行的時候,先獲取 vm 中data實時更新的屬性值,this.value 是vm data中之前的老值
  if (oldValue != value) {
    // console.log('人家通知了,我要改變了')
    // 把剛剛獲取的更新值賦給之前vm data 中的值
    this.value = value 
    // 執行回調函數 具體怎么處理這個,看實際調用時候 callback 的處理 
    this.callback(this.value)
  }
}

4.模板編譯

(為了直接看到頁面數據變化的效果,在模板編譯的核心數據處理上做了dom 操作,下一篇將講模板編譯的一些細節處理)

// dom模板編譯 vm 就是我們最上面的Myvue 對象
function Compile (vm) {
  this.vm = vm;
  this.$el = vm.el;
  // this.data = vm.data;
  this.fragment = null; // 用作后面模板引擎 創建文檔片段
  this.init()
}
Compile.prototype = {
  // init 方法簡單處理,直接做dom 操作,后面會用詳細的模板引擎的學習
  init: function () {
    let value = this.vm.$data.name // 初始化獲取到的值 放進dom節點中
    document.querySelector('.form-control').value = value;
    document.querySelector('.template').textContent = value
    // 通知訂閱者更新dom
    new Watcher(this.vm,this.vm.$prop, (value) => {
      document.querySelector('.form-control').value = value;
      document.querySelector('.template').textContent = value
    })
    document.querySelector('.form-control').addEventListener('input',(e) => {
      let targetValue = e.target.value
      if(value !== targetValue) {
        this.vm.$data.name = e.target.value // 將修改的值 更新到 vm的data中
        document.querySelector('.form-control').value = targetValue; // 更新dom 節點
        document.querySelector('.template').textContent = targetValue
      }
    },false)
  }
}

這樣就可以看到 在表單中,數據的雙向綁定了。

vue 雙向數據綁定的實現學習之監聽器的實現方法

未完待續,錯誤之處,敬請指出,共同進步!

下一篇 vue 雙向數據綁定的實現學習(三)- 模板編譯

附:演示代碼:

js:

function Myvue (options) {
  this.$options = options
  this.$el = document.querySelector(options.el);
  this.$data = options.data;
  Object.keys(this.$data).forEach(key => {
    this.$prop = key;
  })
  this.init()
}
Myvue.prototype.init = function () {
  // 監聽數據變化
  observer(this.$data);
      // 獲得值
      // let value = this.$data[this.$prop];
      // 不經過模板編譯直接 通知訂閱者更新dom
      // new Watcher(this,this.$prop,value => {
      //   console.log(`watcher ${this.$prop}的改動,要有動靜了`)
      //   this.$el.textContent = value
      // }) 
  //通知模板編譯來執行頁面上模板變量替換
  new Compile(this)
}
function observer (data) {
  if(!data || typeof data !== 'object') {
    return;
  }
  Object.keys(data).forEach(key => {
    // 對每個屬性監聽處理
    defineReactive(data, key, data[key]);
  })
}
function defineReactive (data,key,value) {
  // 每次訪問/修改屬性的時候 實例化一個調度中心Dep
  var dep = new Dep();
  Object.defineProperty(data,key,{
    get: function() {
      // 添加到watcher 的Dep 調度中心
      if (Dep.target) { // Dep.target 是個什么鬼? 轉到watcher.js 它是某個訂閱者 watcher
        dep.addSub(Dep.target); //這個代碼段的意思: 如果有訂閱者(訪問/修改屬性的時候) 就將這個訂閱者統一放進 Dep 調度中心中
      }
      // console.log(`${key}屬性被訪問了`)
      return value
    },
    set: function (newValue) {
      if (value != newValue) {
        // console.log(`${key}屬性被重置了`)
        value = newValue
        dep.notify(); //我這里有做改動了,通知調度中心的notify方法
      }
    }
  })
  // 遞歸調用,observe 這個value
  observer(value)
}
// 統一管理watcher訂閱者的Dep (調度中心) Dispatch center
function Dep () {
  // 所有的watcher 放進這里統一管理
  this.subs = []
}
Dep.target = null;
// 通知視圖更新dom的 notify的方法
Dep.prototype.notify  = function () {
  // this.subs 是上面訂閱器watcher 的集合
  this.subs.forEach(sub => {
    // sub 是某個Watcher 具體調用某個Watcher的update 方法
    sub.update()
  })
}
// 添加訂閱者的方法
Dep.prototype.addSub = function (sub) {
  this.subs.push(sub)
}
// 具體的訂閱器Watcher
// 傳入一個vue 的示例, 監聽的屬性, 以及處理的回調函數
function Watcher (vm,prop,callback) {
  this.vm = vm;
  this.$prop = prop;
  this.value = this.get();
  this.callback = callback; // 具體watcher所具有的方法,不同的watcher 不同的回調函數,處理不同的業務邏輯
 }
// 添加watcher 獲得屬性的get 方法,當有屬性訪問/設置 的時候,就產生訂閱者 將這個訂閱者放進調度中心
Watcher.prototype.get = function () {
  Dep.target = this;
  // 獲得屬性值
  const value = this.vm.$data[this.$prop];
  return value
}
// 添加watcher的更新視圖的方法
Watcher.prototype.update = function () {
  // 當屬性值有變化的時候,執行方法,更新試圖
  const value = this.vm.$data[this.$prop];
  const oldValue = this.value;
  // update 執行的時候,先獲取 vm 中data實時更新的屬性值,this.value 是vm data中之前的老值
  if (oldValue != value) {
    // console.log('人家通知了,我要改變了')
    // 把剛剛獲取的更新值賦給之前vm data 中的值
    this.value = value 
    // 執行回調函數 具體怎么處理這個,看實際調用時候 callback 的處理 
    this.callback(this.value)
  }
}
// dom模板編譯 vm 就是我們最上面的Myvue 對象
function Compile (vm) {
  this.vm = vm;
  this.$el = vm.el;
  // this.data = vm.data;
  this.fragment = null; // 用作后面模板引擎 創建文檔片段
  this.init()
}
Compile.prototype = {
  // init 方法簡單處理,直接做dom 操作,后面會用詳細的模板引擎的學習
  init: function () {
    let value = this.vm.$data.name // 初始化獲取到的值 放進dom節點中
    document.querySelector('.form-control').value = value;
    document.querySelector('.template').textContent = value
    // 通知訂閱者更新dom
    new Watcher(this.vm,this.vm.$prop, (value) => {
      document.querySelector('.form-control').value = value;
      document.querySelector('.template').textContent = value
    })
    document.querySelector('.form-control').addEventListener('input',(e) => {
      let targetValue = e.target.value
      if(value !== targetValue) {
        this.vm.$data.name = e.target.value // 將修改的值 更新到 vm的data中
        document.querySelector('.form-control').value = targetValue; // 更新dom 節點
        document.querySelector('.template').textContent = targetValue
      }
    },false)
  }
}

html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Vue雙向綁定原理及實現</title>
    <link rel="stylesheet"  integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh5u"
    crossorigin="anonymous">
    <style>
      #app {
        margin: 20px auto;
        width: 400px;
        padding: 50px;
        text-align: center;
        border: 2px solid #ddd;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <input class="form-control" v-model="name" type="text">
      <h2 class="template">{{name}}</h2>
    </div>
    <script src="./js/index1.js"></script>
    <script>
      const vm = new Myvue({
        el: "#app",
        data: {
          name: "vue 雙向數據綁定test1"
        }
      });
    </script>
  </body>
</html>

總結

以上所述是小編給大家介紹的vue 雙向數據綁定的實現學習之監聽器的實現方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對創新互聯網站的支持!

網頁名稱:vue雙向數據綁定的實現學習之監聽器的實現方法
文章路徑:http://www.2m8n56k.cn/article30/gpocpo.html

成都網站建設公司_創新互聯,為您提供搜索引擎優化關鍵詞優化小程序開發商城網站手機網站建設App設計

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:[email protected]。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

網站建設網站維護公司
主站蜘蛛池模板: 日韩a级片 | 国产成人精品福利网站在线 | 国产精品漂亮美女在线观看 | 国产午夜精品久久理论片小说 | 国产一区二区在线不卡 | 日韩 欧美 自拍 在线 视频 | 成人在线黄色 | 国产免费一级高清淫曰本片 | 手机在线播放av | 毛片大全免费 | 美女视频黄在线观看 | 自偷自偷自亚洲永久 | 美女扒开腿让男人桶 | 国产黄色一级网站 | 成年人网站黄 | 国产免费播放一区二区 | 高清在线观看自拍视频 | 欧美三级成版人版在线观看 | 91久久亚洲精品国产一区二区 | 欧美亚洲国产精品久久 | 免费五级在线观看日本片 | 一区二区三区高清视频在线观看 | 久夜色精品国产一区二区三区 | 免费人成在观看 | 中文字幕 亚洲精品 第1页 | 欧美一区二区三区久久综 | 中文字幕 亚洲精品 | 久草视频资源在线 | 久久免费精品视频 | 国产日韩精品一区在线不卡 | 亚洲依依成人综合在线网址 | 国产精品网站 夜色 | 国产a一级毛片含羞草传媒 国产a自拍 | 男女乱淫真视频免费观看 | 99热热久久这里只有精品166 | 台湾精品视频在线观看 | 精品国产三级v | 激情6月丁香婷婷色综合 | 国产性大片黄在线观看在线放 | 久久99国产乱子伦精品免费 | 亚洲国产成人久久一区二区三区 |