日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

vue 數據雙向綁定的實現方法

瀏覽:21日期:2022-10-04 08:14:09
1. 前言

本文適合于學習Vue源碼的初級學者,閱讀后,你將對Vue的數據雙向綁定原理有一個大致的了解,認識Observer、Compile、Wathcer三大角色(如下圖所示)以及它們所發揮的功能。

本文將一步步帶你實現簡易版的數據雙向綁定,每一步都會詳細分析這一步要解決的問題以及代碼為何如此寫,因此,在閱讀完本文后,希望你能自己動手實現一個簡易版數據雙向綁定。

vue 數據雙向綁定的實現方法

2. 代碼實現2.1 目的分析

本文要實現的效果如下圖所示:

vue 數據雙向綁定的實現方法

本文用到的HTML和JS主體代碼如下:

<div id='app'> <h1 v-text='msg'></h1> <input type='text' v-model='msg'> <div> <h1 v-text='msg2'></h1> <input type='text' v-model='msg2'> </div></div>

let vm = new Vue({ el: '#app', data: { msg: 'hello world', msg2: 'hello xiaofei' } })

我們將按照下面三個步驟來實現:

第一步:將data中的數據同步到頁面上,實現 M ==> V 的初始化; 第二步:當input框中輸入值時,將新值同步到data中,實現 V ==> M 的綁定; 第三步:當data數據發生更新的時候,觸發頁面發生變化,實現 M ==> V 的綁定。 2.2 實現過程2.2.1 入口代碼

首先,我們要創造一個Vue類,這個類接收一個 options 對象,同時,我們要對 options 對象中的有效信息進行保存;

然后,我們有三個主要模塊:Observer、Compile、Wathcer,其中,Observer用來數據劫持的,Compile用來解析元素,Wathcer是觀察者。可以寫出如下代碼:(Observer、Compile、Wathcer這三個概念,不用細究,后面會詳解講解)。

class Vue { // 接收傳進來的對象 constructor(options) { // 保存有效信息 this.$el = document.querySelector(options.el); this.$data = options.data; // 容器: {屬性1: [wathcer1, wathcer2...], 屬性2: [...]},用來存放每個屬性觀察者 this.$watcher = {}; // 解析元素: 實現Compile this.compile(this.$el); // 要解析元素, 就得把元素傳進去 // 劫持數據: 實現 Observer this.observe(this.$data); // 要劫持數據, 就得把數據傳入 } compile() {} observe() {} }2.2.2 頁面初始化

在這一步,我們要實現頁面的初始化,即解析出v-text和v-model指令,并將data中的數據渲染到頁面中。

這一步的關鍵在于實現compile方法,那么該如何解析el元素呢?思路如下:

首先要獲取到el下面的所有子節點,然后遍歷這些子節點,如果子節點還有子節點,那我們就需要用到遞歸的思想; 遍歷子節點找到所有有指令的元素,并將對應的數據渲染到頁面中。

代碼如下:(主要看compile那部分)

class Vue { // 接收傳進來的對象 constructor(options) { // 獲取有用信息 this.$el = document.querySelector(options.el); this.$data = options.data; // 容器: {屬性1: [wathcer1, wathcer2...], 屬性2: [...]} this.$watcher = {}; // 2. 解析元素: 實現Compile this.compile(this.$el); // 要解析元素, 就得把元素傳進去 // 3. 劫持數據: 實現 Observer this.observe(this.$data); // 要劫持數據, 就得把數據傳入 } compile(el) { // 解析元素下的每一個子節點, 所以要獲取el.children // 備注: children 返回元素集合, childNodes返回節點集合 let nodes = el.children; // 解析每個子節點的指令 for (var i = 0, length = nodes.length; i < length; i++) {let node = nodes[i];// 如果當前節點還有子元素, 遞歸解析該節點if(node.children){ this.compile(node);}// 解析帶有v-text指令的元素if (node.hasAttribute('v-text')) { let attrVal = node.getAttribute('v-text'); node.textContent = this.$data[attrVal]; // 渲染頁面}// 解析帶有v-model指令的元素if (node.hasAttribute('v-model')) { let attrVal = node.getAttribute('v-model'); node.value = this.$data[attrVal];} } } observe(data) {} }

這樣,我們就實現頁面的初始化了。

vue 數據雙向綁定的實現方法

2.2.3 視圖影響數據

因為input帶有v-model指令,因此我們要實現這樣一個功能:在input框中輸入字符,data中綁定的數據發生相應的改變。

我們可以在input這個元素上綁定一個input事件,事件的效果就是:將data中的相應數據修改為input中的值。

這一部分的實現代碼比較簡單,只要看標注那個地方就明白了,代碼如下:

class Vue { constructor(options) { this.$el = document.querySelector(options.el); this.$data = options.data; this.$watcher = {};this.compile(this.$el); this.observe(this.$data); } compile(el) { let nodes = el.children; for (var i = 0, length = nodes.length; i < length; i++) {let node = nodes[i];if(node.children){ this.compile(node);}if (node.hasAttribute('v-text')) { let attrVal = node.getAttribute('v-text'); node.textContent = this.$data[attrVal];}if (node.hasAttribute('v-model')) { let attrVal = node.getAttribute('v-model'); node.value = this.$data[attrVal]; // 看這里!!只多了三行代碼!! node.addEventListener('input', (ev)=>{ this.$data[attrVal] = ev.target.value; // 可以試著在這里執行:console.log(this.$data), // 就可以看到每次在輸入框輸入文字的時候,data中的msg值也發生了變化 })} } } observe(data) {} }2.2.4 數據影響視圖

至此,我們已經實現了:當我們在input框中輸入字符的時候,data中的數據會自動發生更新;

本小節的主要任務是:當data中的數據發生更新的時候,綁定了該數據的元素會在頁面上自動更新視圖。具體思路如下:

1) 我們將要實現一個 Wathcer 類,它有一個update方法,用來更新頁面。觀察者的代碼如下:

class Watcher{ constructor(node, updatedAttr, vm, expression){ // 將傳進來的值保存起來,這些數據都是渲染頁面時要用到的數據 this.node = node; this.updatedAttr = updatedAttr; this.vm = vm; this.expression = expression; this.update(); } update(){ this.node[this.updatedAttr] = this.vm.$data[this.expression]; } }

2) 試想,我們該給哪些數據添加觀察者?何時給數據添加觀察者?

在解析元素的時候,當解析到v-text和v-model指令的時候,說明這個元素是需要和數據雙向綁定的,因此我們在這時往容器中添加觀察者。我們需用到這樣一個數據結構:{屬性1: [wathcer1, wathcer2...], 屬性2: [...]},如果不是很清晰,可以看下圖:

vue 數據雙向綁定的實現方法

可以看到:vue實例中有一個$wathcer對象,$wathcer的每個屬性對應每個需要綁定的數據,值是一個數組,用來存放觀察了該數據的觀察者。(備注:Vue源碼中專門創造了Dep這么一個類,對應這里所說的數組,本文屬于簡易版本,就不過多介紹了)

3) 劫持數據:利用對象的訪問器屬性getter和setter做到當數據更新的時候,觸發一個動作,這個動作的主要目的就是讓所有觀察了該數據的觀察者執行update方法。

總結一下,在本小節我們需要做的工作:

實現一個Wathcer類; 在解析指令的時候(即在compile方法中)添加觀察者; 實現數據劫持(實現observe方法)。

完整代碼如下:

class Vue { // 接收傳進來的對象 constructor(options) { // 獲取有用信息 this.$el = document.querySelector(options.el); this.$data = options.data; // 容器: {屬性1: [wathcer1, wathcer2...], 屬性2: [...]} this.$watcher = {}; // 解析元素: 實現Compile this.compile(this.$el); // 要解析元素, 就得把元素傳進去 // 劫持數據: 實現 Observer this.observe(this.$data); // 要劫持數據, 就得把數據傳入 } compile(el) { // 解析元素下的每一個子節點, 所以要獲取el.children // 拓展: children 返回元素集合, childNodes返回節點集合 let nodes = el.children; // 解析每個子節點的指令 for (var i = 0, length = nodes.length; i < length; i++) {let node = nodes[i];// 如果當前節點還有子元素, 遞歸解析該節點if (node.children) { this.compile(node);}if (node.hasAttribute('v-text')) { let attrVal = node.getAttribute('v-text'); // node.textContent = this.$data[attrVal]; // Watcher在實例化時調用update, 替代了這行代碼 /** * 試想Wathcer要更新節點數據的時候要用到哪些數據? * e.g. p.innerHTML = vm.$data[msg] * 所以要傳入的參數依次是: 當前節點node, 需要更新的節點屬性, vue實例, 綁定的數據屬性 */ // 往容器中添加觀察者: {msg1: [Watcher, Watcher...], msg2: [...]} if (!this.$watcher[attrVal]) { this.$watcher[attrVal] = []; } this.$watcher[attrVal].push(new Watcher(node, 'innerHTML', this, attrVal))}if (node.hasAttribute('v-model')) { let attrVal = node.getAttribute('v-model'); node.value = this.$data[attrVal]; node.addEventListener('input', (ev) => { this.$data[attrVal] = ev.target.value; }) if (!this.$watcher[attrVal]) { this.$watcher[attrVal] = []; } // 不同于上處用的innerHTML, 這里input用的是vaule屬性 this.$watcher[attrVal].push(new Watcher(node, 'value', this, attrVal))} } } observe(data) { Object.keys(data).forEach((key) => {let val = data[key]; // 這個val將一直保存在內存中,每次訪問data[key],都是在訪問這個valObject.defineProperty(data, key, { get() { return val; // 這里不能直接返回data[key],不然會陷入無限死循環 }, set(newVal) { if (val !== newVal) { val = newVal;// 同理,這里不能直接對data[key]進行設置,會陷入死循環 this.$watcher[key].forEach((w) => {w.update(); }) } }}) }) } } class Watcher { constructor(node, updatedAttr, vm, expression) { // 將傳進來的值保存起來 this.node = node; this.updatedAttr = updatedAttr; this.vm = vm; this.expression = expression; this.update(); } update() { this.node[this.updatedAttr] = this.vm.$data[this.expression]; } } let vm = new Vue({ el: '#app', data: { msg: 'hello world', msg2: 'hello xiaofei' } })

至此,代碼就完成了。

3. 未來的計劃

用設計模式的知識,分析上面這份源碼存在的問題,并和Vue源碼進行比對,算是對Vue源碼的解析

以上就是vue 數據雙向綁定的實現方法的詳細內容,更多關于vue 數據雙向綁定的資料請關注好吧啦網其它相關文章!

標簽: Vue
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产精品.xx视频.xxtv| 欧美三区四区| 国产精品丝袜在线播放| 精品精品99| 欧美福利一区| 欧美一区不卡| 一区二区精品伦理...| 亚洲少妇自拍| 国产精品xvideos88| 久久免费高清| 国产视频亚洲| 在线人成日本视频| 亚洲h色精品| 欧美日韩水蜜桃| 国产欧洲在线| 欧美三区四区| 一区二区小说| 一二三区精品| 国产精品日本一区二区不卡视频| 精品无人区麻豆乱码久久久| 国产综合色区在线观看| 成人亚洲精品| 久久精品国产www456c0m| 亚洲欧美视频一区二区三区| 欧美日韩国产一区二区在线观看| 国产剧情在线观看一区| 香蕉久久精品| 国产美女撒尿一区二区| 国产主播一区| 欧美亚洲一区二区三区| 日韩精品欧美| 久久国产欧美日韩精品| 尤物网精品视频| 精品国产乱码久久久久久樱花| 黄色成人精品网站| 成人免费一区| 久久精品72免费观看| 狠狠爱成人网| 日本久久综合| 日韩精彩视频在线观看| 亚洲国产日韩欧美在线| 国产一区二区三区黄网站| 视频一区日韩精品| 国产在线不卡| 国产在线一区不卡| 日本在线视频一区二区| 亚洲激情中文| 国产精品99一区二区三区| 日韩三级久久| 亚洲一区激情| 欧美不卡高清一区二区三区| 国产精品尤物| 中文字幕日韩亚洲| 91国语精品自产拍| 日韩在线观看一区| 你懂的国产精品永久在线| 亚洲男人在线| 伊人精品在线| 久久精品青草| 狠狠久久伊人| 国产精品羞羞答答在线观看| 一本色道精品久久一区二区三区| 九九色在线视频| 国产第一亚洲| 免费看久久久| 国产欧美啪啪| 日韩高清欧美激情| 伊人国产精品| 亚洲在线电影| 免费不卡中文字幕在线| 在线天堂中文资源最新版| 免费在线欧美黄色| 国产日韩在线观看视频| 日本特黄久久久高潮| 蜜桃免费网站一区二区三区 | 欧美私人啪啪vps| 免费精品视频| 国产精品美女| 亚洲激情黄色| 亚洲激情av| 99成人在线| 亚洲美洲欧洲综合国产一区| 最新亚洲激情| 99国产精品自拍| 亚洲国产专区| 国产中文一区| 好看不卡的中文字幕| 婷婷亚洲五月| 伊人久久成人| 夜夜嗨网站十八久久| 国产精品日韩欧美一区| 99热精品在线| 噜噜噜躁狠狠躁狠狠精品视频 | 亚洲黑丝一区二区| 婷婷成人基地| 视频在线在亚洲| 亚洲啊v在线免费视频| 亚洲三级视频| 日本视频中文字幕一区二区三区| 国产探花一区二区| 国产精品探花在线观看| 国产日产精品_国产精品毛片 | 欧美羞羞视频| 成人羞羞在线观看网站| 亚洲成人国产| 在线精品视频在线观看高清| 性欧美精品高清| 亚洲精品成人一区| 国产乱人伦精品一区| 久久精品国产一区二区| 亚洲欧洲高清| 色在线中文字幕| 亚洲高清激情| 亚洲在线观看| 日韩久久一区| 麻豆精品一区二区综合av| 久久电影tv| 美女少妇全过程你懂的久久| 国产精品日韩久久久| 日本伊人久久| 精品一区二区三区中文字幕| 一本大道色婷婷在线| 国产一区二区中文| 蜜臀va亚洲va欧美va天堂 | 精品理论电影在线| 日韩精品一卡| 久久国产精品99国产| 日韩超碰人人爽人人做人人添| 国产精品99久久免费| 亚洲va中文在线播放免费| 欧美日韩视频| 欧美在线91| 亚洲永久av| 蜜桃av一区| 国产精品mv在线观看| 亚洲成人一区在线观看| 蜜芽一区二区三区| 国产精品视频首页| 欧洲av不卡| 亚洲色图网站| 另类小说一区二区三区| 欧美日韩第一| 欧美影院视频| 欧洲精品一区二区三区| 日韩在线一二三区| 精品视频国内| 在线一区欧美| 国产精品99久久免费观看| 久久久久国产精品一区三寸| 亚洲麻豆一区| 丁香婷婷久久| 视频一区二区三区入口| 国产成人调教视频在线观看| 红桃视频国产精品| 久久wwww| 亚洲激情二区| 国产精品亚洲欧美一级在线| 99久久精品网| 国产欧美日韩在线一区二区| 欧美 日韩 国产一区二区在线视频 | 亚洲婷婷免费| 日本h片久久| 天堂日韩电影| 欧美日本精品| 亚洲大全视频| 美女精品久久| 香蕉久久夜色精品国产| 激情中国色综合| 日韩一区二区三区四区五区| 久久狠狠婷婷| 国产精品三级| 免费国产亚洲视频| 亚洲综合在线电影| 欧美日韩中文| 亚洲欧洲一区| 国产成人调教视频在线观看| 久久av一区| 久久中文亚洲字幕| 国精品一区二区三区| 欧美久久久网站| 久久久久久久久丰满| 青草综合视频| 欧美成a人免费观看久久| 午夜精品影视国产一区在线麻豆| 国产精品99一区二区三| 麻豆久久精品| 精品国产乱码| 日韩中文字幕91| 一区二区电影| 国产精品中文字幕制服诱惑| 亚洲尤物在线| 日韩国产欧美| 国产黄色一区| 日韩精品久久理论片| 在线亚洲精品| 欧美日韩中文字幕一区二区三区 | 免播放器亚洲| 天堂8中文在线最新版在线| 日韩高清在线一区| 亚洲精品中文字幕乱码|