国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

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

2019-11-19 12:26:32
字體:
來源:轉載
供稿:網友

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

1.先看如何調用

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

上面看到了在實例化一個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 centerfunction 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 雙向數據綁定的實現學習(三)- 模板編譯

附:演示代碼:

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 centerfunction 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/K68vbdEjh4u"    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">      <h1 class="template">{{name}}</h1>    </div>    <script src="./js/index1.js"></script>    <script>      const vm = new Myvue({        el: "#app",        data: {          name: "vue 雙向數據綁定test1"        }      });    </script>  </body></html>

總結

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 扬中市| 靖宇县| 兰溪市| 清水河县| 沁阳市| 新兴县| 定日县| 莲花县| 杨浦区| 鲁甸县| 福建省| 建瓯市| 武宁县| 景洪市| 岳西县| 大埔县| 邯郸市| 蕲春县| 宣武区| 三穗县| 酒泉市| 花莲市| 台东市| 历史| 绥阳县| 安化县| 宜兰市| 邻水| 宁河县| 金沙县| 五华县| 白玉县| 洪湖市| 孝昌县| 遂川县| 罗田县| 承德市| 郑州市| 松阳县| 岚皋县| 阿荣旗|