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

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

vue mvvm數據響應實現

瀏覽:22日期:2022-11-01 17:16:03

為什么實現數據響應式

當前vue、react等框架流行。無論是vue、還是react框架大家最初的設計思路都是類似的。都是以數據驅動視圖,數據優先。希望能夠通過框架減少開發人員直接操作節點,讓開發人員能夠把更多的精力放在業務上而不是過多的放在操作節點上。另一方面,框架會通過虛擬dom及diff算法提高頁面性能。這其中需要數據優先最根本的思路就是實現數據響應式。so,本次來看下如何基于原生實現數據響應式。

vue中的數據響應

vue中會根據數據將數據通過大胡子語法及指令渲染到視圖上,這里我們以大胡子語法為例。如下:

<div id='app'> {{message}}</div>

let vm = new Vue({ el:'#app', data:{ message:'測試數據' }})setTimeout(()=>{ vm.message = '修改的數據';},1000)

如上代碼,很簡單 。vue做了兩件事情。一、把message數據初次渲染到視圖。二、當message數據改變的時候視圖上渲染的message數據同時也會做出響應。以最簡單的案例。帶著問題來看,通過原生js如何實現??這里為了簡化操作便于理解,這里就不去使用虛擬dom。直接操作dom結構。

實現數據初次渲染

根據vue調用方式。定義Vue類來實現各種功能。將初次渲染過程定義成編譯compile函數渲染視圖。通過傳入的配置以及操作dom來實現渲染。大概思路是通過正則查找html 里 #app 作用域內的表達式,然后查找數據做對應的替換即可。具體實現如下:

class Vue { constructor(options) { this.opts = options; this.compile(); } compile() { let ele = document.querySelector(this.opts.el); // 獲取所有子節點 let childNodes = ele.childNodes; childNodes.forEach(node => { if (node.nodeType === 3) {// 找到所有的文本節點let nodeContent = node.textContent;// 匹配“{{}}”let reg = /{{s*([^{}s]+)s*}}/g;if (reg.test(nodeContent)) { let $1 = RegExp.$1; // 查找數據替換 “{{}}” node.textContent = node.textContent.replace(reg, this.opts.data[$1]);} } }) }}

如上完成了初次渲染,將message數據渲染到了視圖上。但是會返現并沒對深層次的dom結構做處理也就是如下情況:

<div id='app'> 1{{ message }}2 <div> hello , {{ message }} </div> </div>

vue mvvm數據響應實現

渲染結果如上

發現結果并沒有達到預期。so,需要改下代碼,讓節點可以深層次查找就可以了。代碼如下:

compile() { let ele = document.querySelector(this.opts.el); this.compileNodes(ele); } compileNodes(ele) { // 獲取所有子節點 let childNodes = ele.childNodes; childNodes.forEach(node => { if (node.nodeType === 3) {// 找到所有的文本節點let nodeContent = node.textContent;// 匹配“{{}}”let reg = /{{s*([^{}s]+)s*}}/g;if (reg.test(nodeContent)) { let $1 = RegExp.$1; // 查找數據替換 “{{}}” node.textContent = node.textContent.replace(reg, this.opts.data[$1]);} } else if (node.nodeType === 1) {if (node.childNodes.length > 0) { this.compileNodes(node);} } }) }

上述代碼通過遞歸查找節點 實現深層次節點的渲染工作。如此,就實現了視圖的初次渲染。

數據劫持

回過頭來看下上面說的第二個問題:當message數據改變的時候視圖上渲染的message數據同時也會做出響應。如何實現數據響應式?簡而言之就是數據變動影響視圖變動?再將問題拆分下 1. 如何知道數據變動了? 2.如何根據數據變動來更改視圖?

如何知道數據變動了? 這里就需要用到數據攔截了,或者叫數據觀察。把會變動的data數據觀察起來。當他變動的時候我們可以做后續的渲染事情。如何攔截數據呢 ?vue2里采取的是definePrototype。

let obj = { myname:'張三'}Object.defineProperty(obj,’myname’,{ configurable:true, enumerable:true, get(){ console.log('get.') return '張三'; }, set(newValue){ console.log('set') console.log(newValue); }})console.log(obj);

上述代碼會發現,通過defineProperty劫持的對象屬性下都會有get及set方法。那么當我們獲取或者設置數據的時候就能出發對應的get及set 。這樣就能攔截數據做后續操作。

vue mvvm數據響應實現

還有沒有其他方式達到數據劫持的效果呢?ES6中出現了Proxy 代理對象同樣也可以達到類似劫持數據的功能。如下代碼:

let obj = { myname:'張三'}let newObj = new Proxy(obj,{ get(target,key){ console.log('get...') return '張三' }, set(target,name,newValue){ console.log('set...'); return Reflect.set(target,name,newValue); }})

兩種方式都可以實現數據劫持。proxy功能更加強大,很多方法是defineProperty所不具備的。且proxy直接攔截的是對象而defineProperty攔截的是對象屬性。so,可以利用上述方式將data數據做劫持,代碼如下:

observe(data){ let keys = Object.keys(data); keys.forEach(key=>{ let value = data[key]; Object.defineProperty(data,key,{configurable:true,enumerable:true,get(){ return value;},set(newValue){ value = newValue;} }); }) }

觀察者模式實現數據響應

有了劫持數據方式后,接下來需要實現的就是當修改數據的時候將新數據渲染到視圖。如何辦到呢?會發現,需要在data設置的時候觸發視圖的compile編譯。二者之間互相影響,此時可以想到利用觀察者模式,通過觀察者模式讓二者產生關聯,如下:

vue mvvm數據響應實現

圖略小,代碼也貼上吧。

class Vue extends EventTarget { constructor(options) { super(); this.opts = options; this.observe(this.opts.data); this.compile(); } observe(data){ let keys = Object.keys(data); let _this = this; keys.forEach(key=>{ let value = data[key]; Object.defineProperty(data,key,{configurable:true,enumerable:true,get(){ return value;},set(newValue){ _this.dispatchEvent(new CustomEvent(key,{ detail:newValue })); value = newValue;} }); }) } compile() { let ele = document.querySelector(this.opts.el); this.compileNodes(ele); } compileNodes(ele) { // 獲取所有子節點 let childNodes = ele.childNodes; childNodes.forEach(node => { if (node.nodeType === 3) {// 找到所有的文本節點let nodeContent = node.textContent;// 匹配“{{}}”let reg = /{{s*([^{}s]+)s*}}/g;if (reg.test(nodeContent)) { let $1 = RegExp.$1; // 查找數據替換 “{{}}” node.textContent = node.textContent.replace(reg, this.opts.data[$1]); this.addEventListener($1,e=>{ let oldValue = this.opts.data[$1]; let newValue = e.detail; let reg = new RegExp(oldValue); node.textContent = node.textContent.replace(reg,newValue); })} } else if (node.nodeType === 1) {if (node.childNodes.length > 0) { this.compileNodes(node);} } }) }}

如上,成功的通過觀察者模式實現了數據的響應。但是會發現data與compile之間需要通過鍵名來進行關聯。如果data數據結構嵌套關系復雜后面會比較難處理。有沒有一種方式讓二者松解耦呢?這時候可以用發布訂閱模式來進行改造。

發布訂閱模式改造響應式

vue mvvm數據響應實現

還是略小,也還是貼上代碼:

class Vue { constructor(options) { this.opts = options; this.observe(this.opts.data); this.compile(); } observe(data){ let keys = Object.keys(data); let _this = this; keys.forEach(key=>{ let value = data[key]; let dep = new Dep(); Object.defineProperty(data,key,{configurable:true,enumerable:true,get(){ if(Dep.target){ dep.addSub(Dep.target); } return value;},set(newValue){ dep.notify(newValue); value = newValue;} }); }) } compile() { let ele = document.querySelector(this.opts.el); this.compileNodes(ele); } compileNodes(ele) { // 獲取所有子節點 let childNodes = ele.childNodes; childNodes.forEach(node => { if (node.nodeType === 3) {// 找到所有的文本節點let nodeContent = node.textContent;// 匹配“{{}}”let reg = /{{s*([^{}s]+)s*}}/g;if (reg.test(nodeContent)) { let $1 = RegExp.$1; // 查找數據替換 “{{}}” node.textContent = node.textContent.replace(reg, this.opts.data[$1]); new Watcher(this.opts.data,$1,(newValue)=>{ let oldValue = this.opts.data[$1]; let reg = new RegExp(oldValue); node.textContent = node.textContent.replace(reg,newValue); })} } else if (node.nodeType === 1) {if (node.childNodes.length > 0) { this.compileNodes(node);} } }) }}class Dep{ constructor(){ this.subs = []; } addSub(sub){ this.subs.push(sub); } notify(newValue){ this.subs.forEach(sub=>{ sub.update(newValue); }) }}class Watcher{ constructor(data,key,cb){ Dep.target = this; data[key]; this.cb = cb; Dep.target = null; } update(newValue){ this.cb(newValue); }}

如上代碼思路是 針對每個數據會生成一個dep(依賴收集器)在數據get的時候收集watcher,將watcher 添加到dep里保存。數據一旦有改變觸發notify發布消息從而影響compile編譯更新視圖。這個流程也可以參看下圖:

vue mvvm數據響應實現

如上就完成了視圖響應。通過上述代碼,我們可以看出實現數據響應兩個核心點1.數據劫持。2.觀察者和發布訂閱。在這我們可以思考一個問題,2個設計模式都是可以實現的但是有什么區別呢?

觀察者與發布訂閱

這里需要從概念來看

觀察者模式:定義一個對象與其他對象之間的一種依賴關系,當對象發生某種變化的時候,依賴它的其它對象都會得到更新,一對多的關系。 發布訂閱模式:是一種消息范式,消息的發送者(稱為發布者)不會將消息直接發送給特定的接收者(稱為訂閱者)。而是將發布的消息分為不同的類別,無需了解哪些訂閱者(如果有的話)可能存在。同樣的,訂閱者可以表達對一個或多個類別的興趣,只接收感興趣的消息,無需了解哪些發布者(如果有的話)存在。

vue mvvm數據響應實現

兩者之間關系,發布訂閱是三者之間關系。發布訂閱會多了一個關系器來組織主題和觀察者之間的關系。這樣做的好處就是松解耦。看上面響應式例子可以看出觀察者需要通過事件名稱來進行關聯。發布訂閱定義dep管理器之后data和compile徹底解耦,讓二者松散解耦。在處理多層數據結構上發布訂閱會更清晰。松解耦能夠應對更多變化,把模塊之間依賴降到最低。發布訂閱廣義上是觀察者模式。

好了 暫時先over 。 如果覺得有收獲的話可以點個贊,贈人玫瑰,手有余香?。。?!

以上就是vue mvvm數據響應實現的詳細內容,更多關于vue mvvm數據響應的資料請關注好吧啦網其它相關文章!

標簽: Vue
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
久久精品人人| 亚洲精品一区二区妖精| 欧美日一区二区在线观看| 久久爱www.| 黑森林国产精品av| 亚洲欧洲午夜| 中文字幕日韩亚洲| 国产精品久久久久久久久久齐齐| 国产91在线播放精品| 91久久黄色| 欧美一区激情| 美女福利一区二区三区| 亚洲自啪免费| 国产精品.xx视频.xxtv| 日韩精品网站| 日本不卡高清视频| 成人影视亚洲图片在线| 99日韩精品| 久久超级碰碰| 中文欧美日韩| 精品国产鲁一鲁****| 午夜亚洲福利在线老司机| 国产亚洲欧美日韩在线观看一区二区| 97精品在线| 亚洲乱码久久| 日韩一区二区三区免费播放| 亚洲精品三级| 日韩精品电影| 亚欧成人精品| 91看片一区| 天堂俺去俺来也www久久婷婷| а√天堂8资源在线| 蜜桃久久精品一区二区| 午夜久久中文| 国产日本精品| 99热免费精品| 成人三级高清视频在线看| 水野朝阳av一区二区三区| 正在播放日韩精品| 日韩不卡一区二区| 婷婷综合网站| 精品一二三区| 亚洲精品婷婷| 亚洲天堂黄色| 激情综合婷婷| 97成人在线| 午夜日韩福利| 捆绑调教日本一区二区三区| 欧美亚洲三区| 免费人成精品欧美精品| 日韩国产专区| 欧美国产日韩电影| 欧美专区18| 国产一在线精品一区在线观看| 精品视频网站| 欧美日韩伊人| 免费视频最近日韩| 久久国产精品成人免费观看的软件| 国产精品久久乐| 日韩一区二区三免费高清在线观看 | 妖精视频成人观看www| 国产精品2区| 日韩精品国产精品| 国产真实久久| 日韩亚洲一区在线| 久久久精品国产**网站| 日韩和欧美的一区| 久久午夜精品| 免费视频国产一区| 日韩国产一区二区三区| 久久精品国产亚洲aⅴ| 久久精品 人人爱| 日韩精选在线| 亚洲1区在线观看| 伊人www22综合色| 99riav1国产精品视频| 国内精品99| 免费观看不卡av| 中文字幕在线视频网站| 国产suv精品一区| 精品一区电影| 国产福利资源一区| 国产精品久久久久久久久久妞妞 | 三级欧美在线一区| 在线视频精品| 午夜欧美视频| 欧美精品一卡| 亚洲性视频h| 国产伊人精品| 亚洲作爱视频| 日韩精品一级二级| 日本 国产 欧美色综合| 国产一区91| 免费成人在线视频观看| 蜜臀国产一区二区三区在线播放 | 日韩国产在线观看| 欧美亚洲人成在线| 国产欧美日韩综合一区在线播放| 91成人在线精品视频| 国产伦理一区| 精品国产中文字幕第一页 | 国产一区二区三区91| 国产一区丝袜| 日韩三区在线| 香蕉精品视频在线观看| 免费欧美日韩| 午夜亚洲福利| 欧美自拍一区| 另类欧美日韩国产在线| 亚洲精品成人图区| 91精品精品| 国产精品社区| 日韩一区二区三区高清在线观看| 91综合久久爱com| 久久久久亚洲精品中文字幕| 精品网站aaa| 亚洲不卡av不卡一区二区| 亚洲激情社区| 日韩欧美中文在线观看| 国产精品欧美日韩一区| 成人午夜毛片| 亚洲午夜精品久久久久久app| 老鸭窝亚洲一区二区三区| 欧美一区精品| 高清一区二区三区av| 国产精品99免费看| 亚洲精品成人一区| 麻豆91精品视频| 欧美色图一区| 日韩黄色免费网站| 久久中文精品| 1024精品久久久久久久久| 亚洲bt欧美bt精品777| 久久97视频| 欧美日韩国产综合网| 人人精品久久| 欧美黄色网页| 少妇精品久久久| 国产精品蜜芽在线观看| 99亚洲精品| 美女av一区| 国产婷婷精品| 欧美国产另类| 亚洲精品一区二区妖精| 久久国产乱子精品免费女| 久久uomeier| 美美哒免费高清在线观看视频一区二区| 国产精品网址| 欧美69视频| 国产精品亚洲一区二区在线观看| 色爱综合av| 国产亚洲久久| 午夜久久影院| 美女久久99| 蜜臀久久99精品久久久久久9| 成人在线免费观看网站| 亚洲香蕉久久| 欧洲av不卡| 久久精品超碰| 99在线精品免费视频九九视| 国产精品天天看天天狠| 亚洲精品电影| 国产一区国产二区国产三区| 日韩影院免费视频| 涩涩av在线| 91精品国产自产观看在线| 精品一区三区| 国产不卡一区| 日韩av一二三| 日韩视频中文| 国产高潮在线| 欧美久久精品| 丝袜脚交一区二区| 欧洲一区二区三区精品| 69精品国产久热在线观看| 99久久久久国产精品| 国产精品色婷婷在线观看| 99在线精品视频在线观看| 成人午夜毛片| 国产日韩欧美在线播放不卡| 在线亚洲免费| 美女福利一区二区三区| 国产精品一线| 亚洲三区欧美一区国产二区| 99久久精品费精品国产| 欧美黄色一区二区| 亚洲综合中文| 激情久久久久久| 福利片在线一区二区| 日韩和欧美的一区| 女同性一区二区三区人了人一| 国产不卡一区| 国产精品亚洲二区| 日韩中文字幕一区二区三区| 日韩精品免费一区二区三区| 美女免费视频一区| 久久国产精品色av免费看| 亚洲人成亚洲精品| 在线一区视频| 午夜精品免费|