亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

用vue的雙向綁定簡單實現一個todo-list的示例代碼

2019-11-19 15:54:33
字體:
來源:轉載
供稿:網友

前言

最近在學習vue框架的基本原理,看了一些技術博客以及一些對vue源碼的簡單實現,對數據代理、數據劫持、模板解析、變異數組方法、雙向綁定有了更深的理解。于是乎,嘗試著去實踐自己學到的知識,用vue的一些基本原理實現一個簡單的todo-list,完成對深度復雜對象的雙向綁定以及對數組的監聽,加深了對vue基本原理的印象。

github地址:todo-list

學習鏈接

前排感謝以下文章,對我理解vue的基本原理有很大的幫助!

剖析vue實現原理,自己動手實現mvvm by DMQ 

對vue早期源碼的理解 by 梁少峰

實現效果

數據代理

1.簡單介紹數據代理

正常情況下,我們都會把數據寫在data里面,如下面所示

var vm = new Vue({  el: '#app',  data: {    title: 'hello world'  }  methods: {    changeTitle: function () {      this.title = 'hello vue'    }  }})console.log(vm.title) // 'hello world' or 'hello vue'

如果沒有數據代理,而我們又要修改data里面的title的話,methods里面的changeTitle只能這樣修改成this.data.title = 'hello vue', 下面的console也只能改成console.log(vm.data.title),數據代理就是這樣的功能。

2. 實現原理

通過遍歷data里面的屬性,將每個屬性通過object.defineProperty()設置getter和setter,將data里面的每個屬性都復制到與data同級的對象里。

(對應上面的示例代碼)

 

觸發這里的getter將會觸發data里面對應屬性的getter,觸發這里的setter將會觸發data里面對應屬性的setter,從而實現代理。實現代碼如下:

var self = this;  // this為vue實例, 即vmObject.keys(this.data).forEach(function(key) {  Object.defineProperty(this, key, {  // this.title, 即vm.title    enumerable: false,    configurable: true,    get: function getter () {      return self.data[key];  //觸發對應data[key]的getter    },    set: function setter (newVal) {      self.data[key] = newVal; //觸發對應data[key]的setter    }  });}

對object.defineProperty不熟悉的小伙伴可以在MDN的文檔(鏈接)學習一下

雙向綁定

  1. 數據變動 ---> 視圖更新
  2. 視圖更新(input、textarea) --> 數據變動

視圖更新 --> 數據變動這個方向的綁定比較簡單,主要通過事件監聽來改變數據,比如input可以監聽input事件,一旦觸發input事件就改變data。下面主要來理解一下數據變動--->視圖更新這個方向的綁定。

1. 數據劫持

不妨讓我們自己思考一下,如何實現數據變動,對應綁定數據的視圖就更新呢?

答案還是object.defineProperty,通過object.defineProperty遍歷設置this.data里面所有屬性,在每個屬性的setter里面去通知對應的回調函數,這里的回調函數包括dom視圖重新渲染的函數、使用$watch添加的回調函數等,這樣我們就通過object.defineProperty劫持了數據,當我們對數據重新賦值時,如this.title = 'hello vue',就會觸發setter函數,從而觸發dom視圖重新渲染的函數,實現數據變動,對應視圖更新。

2. 發布-訂閱模式

那么問題來了,我們如何在setter里面觸發所有綁定該數據的回調函數呢?

既然綁定該數據的回調函數不止一個,我們就把所有的回調函數放在一個數組里面,一旦觸發該數據的setter,就遍歷數組觸發里面所有的回調函數,我們把這些回調函數稱為訂閱者。數組最好就定義在setter函數的最近的上級作用域中,如下面實例代碼所示。

Object.keys(this.data).forEach(function(key) {  var subs = []; // 在這里放置添加所有訂閱者的數組  Object.defineProperty(this.data, key, {  // this.data.title    enumerable: false,    configurable: true,    get: function getter () {      console.log('訪問數據啦啦啦')      return this.data[key];  //返回對應數據的值    },    set: function setter (newVal) {      if (newVal === this.data[key]) {          return;  // 如果數據沒有變動,函數結束,不執行下面的代碼      }      this.data[key] = newVal; //數據重新賦值            subs.forEach(function () {        // 通知subs里面的所有的訂閱者      })    }  });}

那么問題又來了,怎么把綁定數據的所有回調函數放到一個數組里面呢?

我們可以在getter里面做做手腳,我們知道只要訪問數據就會觸發對應數據的getter,那我們可以先設置一個全局變量target,如果我們要在data里面title屬性添加一個訂閱者(changeTitle函數),我們可以先設置target = changeTitle,把changeTitle函數緩存在target中,然后訪問this.title去觸發title的getter,在getter里面把target這個全局變量的值添加到subs數組里面,添加完成后再把全局變量target設置為null,以便添加其他訂閱者。實例代碼如下:

Object.keys(this.data).forEach(function(key) {  var subs = []; // 在這里放置添加所有訂閱者的數組  Object.defineProperty(this.data, key, {  // this.data.title    enumerable: false,    configurable: true,    get: function getter () {      console.log('訪問數據啦啦啦')      if (target) {        subs.push(target);              }      return this.data[key];  //返回對應數據的值    },    set: function setter (newVal) {      if (newVal === this.data[key]) {          return;  // 如果數據沒有變動,函數結束,不執行下面的代碼      }      this.data[key] = newVal; //數據重新賦值            subs.forEach(function () {        // 通知subs里面的所有的訂閱者      })    }  });}

上面的代碼為了方便理解都是通過簡化的,實際上我們把訂閱者寫成一個構造函數watcher,在實例化訂閱者的時候去訪問對應的數據,觸發相應的getter,詳細的代碼可以閱讀DMQ的自己動手實現MVVM

3. 模板解析

通過上面的兩個步驟我們已經實現一旦數據變動,就會通知對應綁定數據的訂閱者,接下來我們來簡單介紹一個特殊的訂閱者,也就是視圖更新函數,幾乎每個數據都會添加對應的視圖更新函數,所以我們就來簡單了解一下視圖更新函數。

假如說有下面這一段代碼,我們怎么把它解析成對應的html呢?

<input v-model="title"><h1>{{title}}</h1><button v-on:click="changeTitle">change title<button>

先簡單介紹視圖更新函數的用途,

比如解析指令v-model="title",v-on:click="changeTitle",還有把{{title}}替換為對應的數據等。

回到上面那個問題,如何解析模板?我們只要去遍歷所有dom節點包括其子節點,

  • 如果節點屬性含有v-model,視圖更新函數就為把input的value設置為title的值
  • 如果節點為文本節點,視圖更新函數就為先用正則表達式取出大括號里面的值'title',再設置文本節點的值為data['title']
  • 如果節點屬性含有v-on:xxxx,視圖更新函數就為先用正則獲取事件類型為click,然后獲取該屬性的值為changeTitle,則事件的回調函數為this.methods['changeTitle'],接著用addEventListener監聽節點click事件。

我們要知道視圖更新函數也是data對應屬性的訂閱者,如果不知道如何觸發視圖更新函數,可以把上面的發布-訂閱模式再看一遍。

可能有的小伙伴可能還有個疑問,如何實現input節點的值變化后,下面的h1節點的title值也發生變化?在遍歷所有節點后,如果節點含有屬性v-model,就用addEventListener監聽input事件,一旦觸發input事件,改變data['title']的值,就會觸發title的setter,從而通知所有的訂閱者。

監聽數組變化

無法監控每個數組元素

如果讓我們自己實現監聽數組的變化,我們可能會想到用object.defineProperty去遍歷數組每個元素并設置setter,但是vue源碼里面卻不是這樣寫的,因為對每一個數組元素defineProperty帶來代碼本身的復雜度增加和代碼執行效率的降低。

變異數組方法

既然無法通過defineProperty監控數組的每個元素,我們可以重寫數組的方法(push, pop, shift, unshift, splice, sort, reverse)來改變數組。

vue文檔中是這樣寫的:

Vue 包含一組觀察數組的變異方法,所以它們也將會觸發視圖更新。這些方法如下:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

下面是vue早期源碼學習系列之二:如何監聽一個數組的變化 中的實例代碼

const aryMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];const arrayAugmentations = [];aryMethods.forEach((method)=> {  // 這里是原生Array的原型方法  let original = Array.prototype[method];  // 將push, pop等封裝好的方法定義在對象arrayAugmentations的屬性上  // 注意:是屬性而非原型屬性  arrayAugmentations[method] = function () {    console.log('我被改變啦!');    // 調用對應的原生方法并返回結果    return original.apply(this, arguments);  };});let list = ['a', 'b', 'c'];// 將我們要監聽的數組的原型指針指向上面定義的空數組對象// 別忘了這個空數組的屬性上定義了我們封裝好的push等方法list.__proto__ = arrayAugmentations;list.push('d'); // 我被改變啦! 4// 這里的list2沒有被重新定義原型指針,所以就正常輸出let list2 = ['a', 'b', 'c'];list2.push('d'); // 4

變異數組方法的缺陷

vue文檔中變異數組方法的缺陷

由于 JavaScript 的限制, Vue 不能檢測以下變動的數組:

  1. 當你利用索引直接設置一個項時,例如: vm.items[indexOfItem] = newValue
  2. 當你修改數組的長度時,例如: vm.items.length = newLength

同時文檔中也介紹了如何解決上面這兩個問題。

最后

以上是自己對vue一些基本原理的理解,當然還有很多不足的地方,歡迎指正。本來自己也是為了應付面試才去學習vue框架的基本原理,但是簡單學習了這些vue基本的原理后,讓我明白通過深入學習框架原理,可以有效避開一些自己以后會遇到的坑,所以,有時間的話自己以后還是會去看看框架的基本原理。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美性xxxxxxxxx| 日韩精品极品在线观看| 亚洲天堂一区二区三区| 中文字幕久精品免费视频| 亚洲欧洲在线视频| 亚洲天堂av图片| 成人精品视频在线| 精品一区电影国产| 国产精品高潮呻吟久久av野狼| 日本a级片电影一区二区| 日韩欧亚中文在线| 亚洲欧美日韩精品久久| 久久精品中文字幕| 在线成人激情视频| 欧美性视频在线| www.日韩.com| 久久av中文字幕| 欧美黄色片免费观看| 亚洲女人天堂av| 中文字幕久精品免费视频| 欧美大片免费观看| 日韩免费在线播放| 亚洲人成电影网站色www| 国产精品色婷婷视频| 中文字幕欧美日韩| 国产精品久久久久久久app| 日韩经典中文字幕| 亚洲色图校园春色| 国产日韩在线观看av| 欧美日韩国产丝袜美女| 欧美日韩中文字幕在线视频| 97在线视频免费观看| 欧美日韩亚洲一区二区三区| 欧美激情手机在线视频| 4k岛国日韩精品**专区| 精品日韩美女的视频高清| 欧美中文在线观看国产| 中文字幕国产精品久久| 欧美第一黄网免费网站| 日本久久久a级免费| 上原亚衣av一区二区三区| 91精品国产一区| 欧美成人久久久| 91国产视频在线| 日韩欧美亚洲国产一区| 欧美俄罗斯性视频| 亚洲精品国产美女| 91网站在线免费观看| 在线播放国产一区中文字幕剧情欧美| 日韩成人在线网站| 欧美精品免费在线| 亚洲精品国产美女| 久久影视电视剧免费网站| 亚洲人成在线播放| 一本大道亚洲视频| 久久精品亚洲国产| 81精品国产乱码久久久久久| 亚洲天堂av电影| 亚洲最大福利视频网站| 欧美性高潮在线| 国产成人午夜视频网址| 日韩禁在线播放| 成人中心免费视频| 成人国产亚洲精品a区天堂华泰| 日韩电影中文 亚洲精品乱码| 日韩高清免费在线| 欧美黄色三级网站| 国产一区二区三区久久精品| 日韩精品免费在线视频| 精品国产网站地址| 久久99精品久久久久久噜噜| 中文字幕欧美日韩| 亚洲欧美成人网| 91亚洲精品一区| 欧美多人乱p欧美4p久久| 国产精品女人网站| 欧美激情精品久久久久久久变态| 亚洲视频电影图片偷拍一区| 中文字幕日本精品| 亚洲成年网站在线观看| 人人爽久久涩噜噜噜网站| 97国产精品久久| 国产精品日韩电影| 亚洲欧美激情精品一区二区| 中文字幕一精品亚洲无线一区| 成人免费视频在线观看超级碰| 欧美在线国产精品| 亚洲成人网av| 精品国产一区av| 992tv在线成人免费观看| 国产精品小说在线| 亚洲xxxx妇黄裸体| 国内成人精品一区| 欧美电影免费播放| 亚洲www在线| 欧美亚洲成人网| 国产午夜精品全部视频播放| 成人乱色短篇合集| 亚洲国产成人精品久久| 久久久久女教师免费一区| 国产精品亚洲欧美导航| 亚洲一区二区日本| 欧美性开放视频| 55夜色66夜色国产精品视频| 亚洲第一中文字幕在线观看| 国产精品96久久久久久| 欧美成aaa人片在线观看蜜臀| 97高清免费视频| 亚洲欧美一区二区精品久久久| 国产精品久久999| 国语自产精品视频在线看抢先版图片| 欧美电影在线免费观看网站| 亚洲精品色婷婷福利天堂| 久久久视频在线| 欧美大尺度电影在线观看| 色综合天天狠天天透天天伊人| 原创国产精品91| 国产日韩欧美一二三区| 一色桃子一区二区| 久久精品国产69国产精品亚洲| 日韩成人在线视频网站| 久久成人精品一区二区三区| 久久久久久国产精品久久| 日韩av免费看网站| 亚洲色图25p| 日韩国产欧美精品一区二区三区| 久久久国产精品一区| 久久久亚洲国产天美传媒修理工| 国产精品jvid在线观看蜜臀| 中文字幕视频一区二区在线有码| 91国内产香蕉| 亚洲a∨日韩av高清在线观看| 欧美激情视频网| 日韩国产激情在线| 欧美电影免费观看| 91日韩在线播放| 国产精品美女www| 久久99久久99精品中文字幕| 欧美诱惑福利视频| 欧美成人手机在线| 91国内揄拍国内精品对白| 成人免费淫片视频软件| 国产精品高清免费在线观看| 久久国产精品视频| 国产成人涩涩涩视频在线观看| 亚洲成人亚洲激情| 国产精品丝袜久久久久久高清| 97久久精品人人澡人人爽缅北| 精品动漫一区二区三区| 亚洲欧美制服另类日韩| 性欧美在线看片a免费观看| 78色国产精品| 欧美第一页在线| 久久久久久久国产精品视频| 九色91av视频| 亚洲国产一区二区三区在线观看| 欧美成人午夜激情视频| 精品久久久久久久大神国产| 亚洲精品久久久久久久久久久久| 亚洲欧美国产高清va在线播| 影音先锋欧美精品| 国产精品福利在线观看| 欧美激情视频播放| 一本一道久久a久久精品逆3p|