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

您的位置:首頁技術(shù)文章
文章詳情頁

Vue Object.defineProperty及ProxyVue實現(xiàn)雙向數(shù)據(jù)綁定

瀏覽:293日期:2022-11-30 10:48:04

雙向數(shù)據(jù)綁定無非就是,視圖 => 數(shù)據(jù),數(shù)據(jù) => 視圖的更新過程

Vue Object.defineProperty及ProxyVue實現(xiàn)雙向數(shù)據(jù)綁定

以下的方案中的實現(xiàn)思路:

定義一個Vue的構(gòu)造函數(shù)并初始化這個函數(shù)(myVue.prototype._init) 實現(xiàn)數(shù)據(jù)層的更新:數(shù)據(jù)劫持,定義一個 obverse 函數(shù)重寫data的set和get(myVue.prototype._obsever) 實現(xiàn)視圖層的更新:訂閱者模式,定義個 Watcher 函數(shù)實現(xiàn)對DOM的更新(Watcher) 將數(shù)據(jù)和視圖層進行綁定,解析指令v-bind、v-model、v-click(myVue.prototype._compile) 創(chuàng)建Vue實例(new myVue)

1.object.defineproperty方式實現(xiàn)雙向數(shù)據(jù)綁定

<!DOCTYPE html><html> <head> <title>myVue</title> <style> #app{ text-align: center; }</style></head> <body> <div id='app'> <form> <input type='text' v-model='number' /> <button type='button' v-click='increment'>增加</button> </form> <h3 v-bind='number'></h3> </div></body><script> // 定義一個myVue構(gòu)造函數(shù) function myVue(option) { this._init(option) } myVue.prototype._init = function (options) { // 傳了一個配置對象 this.$options = options // options 為上面使用時傳入的結(jié)構(gòu)體,包括el,data,methods this.$el = document.querySelector(options.el) // el是 #app, this.$el是id為app的Element元素 this.$data = options.data // this.$data = {number: 0} this.$methods = options.methods // this.$methods = {increment: function(){}} // _binding保存著model與view的映射關(guān)系,也就是我們前面定義的Watcher的實例。當(dāng)model改變時,我們會觸發(fā)其中的指令類更新,保證view也能實時更新 this._binding = {} this._obsever(this.$data) this._compile(this.$el) } // 數(shù)據(jù)劫持:更新數(shù)據(jù) myVue.prototype._obsever = function (obj) { let _this = this Object.keys(obj).forEach((key) => { // 遍歷obj對象 if (obj.hasOwnProperty(key)) { // 判斷 obj 對象是否包含 key屬性 _this._binding[key] = [] // 按照前面的數(shù)據(jù),_binding = {number: []} 存儲 每一個 new Watcher } let value = obj[key] if (typeof value === ’object’) { //如果值還是對象,則遍歷處理 _this._obsever(value) } Object.defineProperty(_this.$data, key, { enumerable: true, configurable: true, get: () => { // 獲取 value 值 return value }, set: (newVal) => { // 更新 value 值 if (value !== newVal) { value = newVal _this._binding[key].forEach((item) => { // 當(dāng)number改變時,觸發(fā)_binding[number] 中的綁定的Watcher類的更新 item.update() // 調(diào) Watcher 實例的 update 方法更新 DOM }) } } }) }) } // 訂閱者模式: 綁定更新函數(shù),實現(xiàn)對 DOM 元素的更新 function Watcher(el, data, key, attr) { this.el = el // 指令對應(yīng)的DOM元素 this.data = data // this.$data 數(shù)據(jù): {number: 0, count: 0} this.key = key // 指令綁定的值,本例如'number' this.attr = attr // 綁定的屬性值,本例為'innerHTML','value' this.update() } // 比如 H3.innerHTML = this.data.number; 當(dāng)number改變時,會觸發(fā)這個update函數(shù),保證對應(yīng)的DOM內(nèi)容進行了更新 Watcher.prototype.update = function () { this.el[this.attr] = this.data[this.key] } // 將view與model進行綁定,解析指令(v-bind,v-model,v-clickde)等 myVue.prototype._compile = function (el) { // root 為id為app的Element元素,也就是我們的根元素 let _this = this let nodes = Array.prototype.slice.call(el.children) // 將為數(shù)組轉(zhuǎn)化為真正的數(shù)組 nodes.map(node => { if (node.children.length && node.children.length > 0) { // 對所有元素進行遍歷,并進行處理 _this._compile(node) } if (node.hasAttribute(’v-click’)) { // 如果有v-click屬性,我們監(jiān)聽它的onclick事件,觸發(fā)increment事件,即number++ let attrVal = node.getAttribute(’v-click’) node.onclick = _this.$methods[attrVal].bind(_this.$data) // bind是使data的作用域與method函數(shù)的作用域保持一致 } // 如果有v-model屬性,并且元素是INPUT或者TEXTAREA,我們監(jiān)聽它的input事件 if (node.hasAttribute(’v-model’) && (node.tagName === ’INPUT’ || node.tagName === ’TEXTAREA’)) { let attrVal = node.getAttribute(’v-model’) _this._binding[attrVal].push(new Watcher( node, // 對應(yīng)的 DOM 節(jié)點 _this.$data, attrVal, // v-model 綁定的值 ’value’ )) node.addEventListener(’input’, () => { _this.$data[attrVal] = node.value // 使number 的值與 node的value保持一致,已經(jīng)實現(xiàn)了雙向綁定 }) } if (node.hasAttribute(’v-bind’)) { let attrVal = node.getAttribute(’v-bind’) _this._binding[attrVal].push(new Watcher( node, _this.$data, attrVal, // v-bind 綁定的值 ’innerHTML’ )) } }) } window.onload = () => { // 當(dāng)文檔內(nèi)容完全加載完成會觸發(fā)該事件,避免獲取不到對象的情況 new myVue({ el: ’#app’, data: { number: 0, count: 0 }, methods: { increment() { this.number++ }, incre() { this.count++ } } }) }</script> </html>

2.Proxy 實現(xiàn)雙向數(shù)據(jù)綁定

<!DOCTYPE html><html> <head> <title>myVue</title> <style> #app{ text-align: center; }</style></head> <body> <div id='app'> <form> <input type='text' v-model='number' /> <button type='button' v-click='increment'>增加</button> </form> <h3 v-bind='number'></h3> </div></body><script> // 定義一個myVue構(gòu)造函數(shù) function myVue(option) { this._init(option) } myVue.prototype._init = function (options) { // 傳了一個配置對象 this.$options = options // options 為上面使用時傳入的結(jié)構(gòu)體,包括el,data,methods this.$el = document.querySelector(options.el) // el是 #app, this.$el是id為app的Element元素 this.$data = options.data // this.$data = {number: 0} this.$methods = options.methods // this.$methods = {increment: function(){}} this._binding = {} this._obsever(this.$data) this._complie(this.$el) } // 數(shù)據(jù)劫持:更新數(shù)據(jù)myVue.prototype._obsever = function (data) { let _this = this let handler = { get(target, key) { return target[key]; // 獲取該對象上key的值 }, set(target, key, newValue) { let res = Reflect.set(target, key, newValue); // 將新值分配給屬性的函數(shù) _this._binding[key].map(item => { item.update(); }); return res; } }; // 把代理器返回的對象代理到this.$data,即this.$data是代理后的對象,外部每次對this.$data進行操作時,實際上執(zhí)行的是這段代碼里handler對象上的方法 this.$data = new Proxy(data, handler); } // 將view與model進行綁定,解析指令(v-bind,v-model,v-clickde)等 myVue.prototype._complie = function (el) { // el 為id為app的Element元素,也就是我們的根元素 let _this = this let nodes = Array.prototype.slice.call(el.children) // 將為數(shù)組轉(zhuǎn)化為真正的數(shù)組 nodes.map(node => { if (node.children.length && node.children.length > 0) this._complie(node) if (node.hasAttribute(’v-click’)) { // 如果有v-click屬性,我們監(jiān)聽它的onclick事件,觸發(fā)increment事件,即number++ let attrVal = node.getAttribute(’v-click’) node.onclick = _this.$methods[attrVal].bind(_this.$data) // bind是使data的作用域與method函數(shù)的作用域保持一致 } // 如果有v-model屬性,并且元素是INPUT或者TEXTAREA,我們監(jiān)聽它的input事件 if (node.hasAttribute(’v-model’) && (node.tagName === ’INPUT’ || node.tagName === ’TEXTAREA’)) { let attrVal = node.getAttribute(’v-model’)console.log(_this._binding) if (!_this._binding[attrVal]) _this._binding[attrVal] = [] _this._binding[attrVal].push(new Watcher( node, // 對應(yīng)的 DOM 節(jié)點 _this.$data, attrVal, // v-model 綁定的值 ’value’, )) node.addEventListener(’input’, () => { _this.$data[attrVal] = node.value // 使number 的值與 node的value保持一致,已經(jīng)實現(xiàn)了雙向綁定 }) } if (node.hasAttribute(’v-bind’)) { let attrVal = node.getAttribute(’v-bind’) if (!_this._binding[attrVal]) _this._binding[attrVal] = [] _this._binding[attrVal].push(new Watcher( node, _this.$data, attrVal, // v-bind 綁定的值 ’innerHTML’, )) } }) } // 綁定更新函數(shù),實現(xiàn)對 DOM 元素的更新 function Watcher(el, data, key, attr) { this.el = el // 指令對應(yīng)的DOM元素 this.data = data // 代理的對象 this.$data 數(shù)據(jù): {number: 0, count: 0} this.key = key // 指令綁定的值,本例如'num' this.attr = attr // 綁定的屬性值,本例為'innerHTML','value' this.update() } // 比如 H3.innerHTML = this.data.number; 當(dāng)number改變時,會觸發(fā)這個update函數(shù),保證對應(yīng)的DOM內(nèi)容進行了更新 Watcher.prototype.update = function () { this.el[this.attr] = this.data[this.key] } window.onload = () => { // 當(dāng)文檔內(nèi)容完全加載完成會觸發(fā)該事件,避免獲取不到對象的情況 new myVue({ el: ’#app’, data: { number: 0, count: 0 }, methods: { increment() { this.number++ }, incre() { this.count++ } } }) }</script> </html>

3.將上面代碼改成class的寫法

<!DOCTYPE html><html> <head> <title>myVue</title> <style> #app{ text-align: center; }</style></head> <body> <div id='app'> <form> <input type='text' v-model='number' /> <button type='button' v-click='increment'>增加</button> </form> <h3 v-bind='number'></h3> </div></body><script> class MyVue { constructor(options) { // 接收了一個配置對象 this.$options = options // options 為上面使用時傳入的結(jié)構(gòu)體,包括el,data,methods this.$el = document.querySelector(options.el) // el是 #app, this.$el是id為app的Element元素 this.$data = options.data // this.$data = {number: 0} this.$methods = options.methods // this.$methods = {increment: function(){}} this._binding = {} this._obsever(this.$data) this._complie(this.$el) } _obsever (data) { // 數(shù)據(jù)劫持:更新數(shù)據(jù) let _this = this let handler = { get(target, key) { return target[key]; // 獲取該對象上key的值 }, set(target, key, newValue) { let res = Reflect.set(target, key, newValue); // 將新值分配給屬性的函數(shù) _this._binding[key].map(item => { item.update(); }); return res; } }; // 把代理器返回的對象代理到this.$data,即this.$data是代理后的對象,外部每次對this.$data進行操作時,實際上執(zhí)行的是這段代碼里handler對象上的方法 this.$data = new Proxy(data, handler); } _complie(el) { // el 為id為app的Element元素,也就是我們的根元素 let _this = this let nodes = Array.prototype.slice.call(el.children) // 將為數(shù)組轉(zhuǎn)化為真正的數(shù)組 nodes.map(node => { if (node.children.length && node.children.length > 0) this._complie(node) if (node.hasAttribute(’v-click’)) { // 如果有v-click屬性,我們監(jiān)聽它的onclick事件,觸發(fā)increment事件,即number++ let attrVal = node.getAttribute(’v-click’) node.onclick = _this.$methods[attrVal].bind(_this.$data) // bind是使data的作用域與method函數(shù)的作用域保持一致 } // 如果有v-model屬性,并且元素是INPUT或者TEXTAREA,我們監(jiān)聽它的input事件 if (node.hasAttribute(’v-model’) && (node.tagName === ’INPUT’ || node.tagName === ’TEXTAREA’)) { let attrVal = node.getAttribute(’v-model’) if (!_this._binding[attrVal]) _this._binding[attrVal] = [] _this._binding[attrVal].push(new Watcher( node, // 對應(yīng)的 DOM 節(jié)點 _this.$data, attrVal, // v-model 綁定的值 ’value’, )) node.addEventListener(’input’, () => { _this.$data[attrVal] = node.value // 使number 的值與 node的value保持一致,已經(jīng)實現(xiàn)了雙向綁定 }) } if (node.hasAttribute(’v-bind’)) { let attrVal = node.getAttribute(’v-bind’) if (!_this._binding[attrVal]) _this._binding[attrVal] = [] _this._binding[attrVal].push(new Watcher( node, _this.$data, attrVal, // v-bind 綁定的值 ’innerHTML’, )) } }) } } class Watcher { constructor (el, data, key, attr) { this.el = el // 指令對應(yīng)的DOM元素 this.data = data // 代理的對象 this.$data 數(shù)據(jù): {number: 0, count: 0} this.key = key // 指令綁定的值,本例如'num' this.attr = attr // 綁定的屬性值,本例為'innerHTML','value' this.update() } update () { this.el[this.attr] = this.data[this.key] } } window.onload = () => { // 當(dāng)文檔內(nèi)容完全加載完成會觸發(fā)該事件,避免獲取不到對象的情況 new MyVue({ el: ’#app’, data: { number: 0, count: 0 }, methods: { increment() { this.number++ }, incre() { this.count++ } } }) }</script> </html>

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持好吧啦網(wǎng)。

標(biāo)簽: Vue
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
爽好久久久欧美精品| 精品日韩一区| 99精品视频在线观看免费播放| 精品一区二区三区中文字幕| 国产精品第十页| 欧美极品一区二区三区| 精品国产日韩欧美精品国产欧美日韩一区二区三区 | 你懂的国产精品| 久久字幕精品一区| 国产精选在线| 久久国产电影| 久久先锋影音| 国产精品一区二区三区美女 | 国产一卡不卡| 理论片午夜视频在线观看| 国产一区二区三区自拍| 亚洲午夜国产成人| 国产精品久久久久久久久免费高清 | 97精品视频在线看| 久久久噜噜噜| 亚洲一区久久| 国产欧美日韩| 久久久久国产精品一区三寸| 久久国产精品毛片| 欧美国产中文高清| 天堂网在线观看国产精品| 日韩一区欧美二区| 精品丝袜久久| 老司机精品久久| 国产精品三p一区二区| 捆绑调教日本一区二区三区| 久久亚洲国产精品一区二区| 久久久精品国产**网站| 狠狠爱成人网| 国产精品久久久久9999高清| av高清一区| 日本午夜精品久久久| 亚洲一级少妇| 日本久久二区| 久久久9色精品国产一区二区三区| 视频一区二区三区在线| 精品视频91| 免费久久精品视频| 国产欧洲在线| 日韩中出av| 久久中文视频| 美女性感视频久久| 免费成人在线观看| 日韩欧美一区免费| 欧美精品福利| 久久性天堂网| 精品日韩视频| 国产精品亚洲综合久久| 免费视频久久| 久久激情婷婷| 国产福利一区二区三区在线播放| 免费欧美一区| 成人污污视频| 久久国产精品免费精品3p| 精品一区免费| 精品视频国内| 国产麻豆一区二区三区| 日韩专区欧美专区| 欧美成人基地 | 综合亚洲视频| 在线日韩一区| 国产精品久久久久久久免费观看| 日韩精品一区二区三区中文在线| 欧美手机在线| 精品国产99| 国产精品一区二区三区美女 | 免费污视频在线一区| 久久久久黄色| 国产日韩视频在线| 日韩精品成人| 在线国产精品一区| 午夜欧美精品| 亚洲精品在线影院| 成人在线免费观看网站| 欧美国产日本| 国产美女视频一区二区| 日本视频在线一区| 亚洲精品免费观看| 蜜臀久久99精品久久久久久9| 影视先锋久久| 激情久久久久久久| 亚洲福利国产| 欧洲毛片在线视频免费观看| 久久精品亚洲欧美日韩精品中文字幕| 高清av一区| 成人午夜在线| 久久av免费看| 国产欧美高清| 91亚洲无吗| 奇米狠狠一区二区三区| 青青草国产精品亚洲专区无| 日本v片在线高清不卡在线观看| 蜜桃视频在线观看一区二区| 国产美女一区| 中文字幕日韩欧美精品高清在线| 亚洲一区国产一区| 亚洲三级在线| 欧美日韩一区二区三区四区在线观看| 欧美综合精品| 精品国产99| 久久激情网站| 久久成人国产| 中文字幕av一区二区三区人| 亚洲精品乱码日韩| 国产欧美日韩| 精品国产第一福利网站| 久久人人99| 国产成人免费| 激情六月综合| 日韩欧美中文在线观看| 国产日韩在线观看视频| 鲁大师精品99久久久| 成午夜精品一区二区三区软件| 亚洲啊v在线| 国产欧美大片| 日韩精品免费一区二区在线观看| 亚洲精品小说| 亚洲一区激情| 日韩av中文在线观看| 精品伊人久久久| 丝袜av一区| 日韩精品一二区| 国产精品视频首页| 日韩精品电影| 蜜桃久久久久久| 免费在线日韩av| 亚洲一级黄色| 日韩动漫一区| 最新中文字幕在线播放| 欧美在线资源| 久久国产视频网| 日韩欧美字幕| 亚洲少妇诱惑| 国产精品1luya在线播放| 天堂中文在线播放| 亚洲精品美女91| 福利在线免费视频| 性欧美长视频| 国产一区二区亚洲| 久久国产精品亚洲77777| 日韩午夜视频在线| 国产高潮在线| 午夜国产精品视频免费体验区| 亚州av日韩av| 久久久免费人体| 亚洲免费一区二区| 久久一区视频| 午夜久久影院| 精品一区视频| 免费美女久久99| 日韩精品1区| 日本不卡一区二区三区| 亚洲人成在线网站| 国产欧美一区二区三区国产幕精品| 天堂日韩电影| 国产九一精品| 中国女人久久久| 亚洲国产福利| 日韩avvvv在线播放| 激情婷婷久久| 久久99国产精品视频| 日韩精品一区第一页| 麻豆91在线播放| 日韩一区二区久久| 久久不见久久见国语| 久久亚洲影院| 久久久五月天| 国产精品a级| 亚洲tv在线| 亚洲欧洲另类| 久久久久国产精品一区三寸| 国产精品va视频| 一区二区三区国产在线| 神马日本精品| 国内一区二区三区| 国产探花在线精品| 亚洲乱码一区| 日韩精品欧美| 精品黄色一级片| 日本va欧美va瓶| 国产日韩视频| 午夜日韩影院| 亚洲欧美日韩视频二区| 欧美精选视频一区二区| 美女毛片一区二区三区四区最新中文字幕亚洲 | 国产精品亚洲综合在线观看| 久久亚洲图片| 久久亚洲国产| 中文字幕在线视频网站| 欧美激情视频一区二区三区在线播放| 日韩午夜高潮| 欧美色图一区| 成人看片网站| 欧美精品日日操| 青青青免费在线视频|