成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

聊聊Vue中如何實現數據雙向綁定

Vue中如何實現數據雙向綁定?下面本篇文章給大家介紹一下Vue.js數據雙向綁定的實現方法,希望對大家有所幫助!

聊聊Vue中如何實現數據雙向綁定

前端(vue)入門到精通課程,老師在線輔導:聯系老師
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API調試工具:點擊使用

在我們使用vue的時候,當數據發生了改變,界面也會跟著更新,但這并不是理所當然的,我們修改數據的時候vue是如何監聽數據的改變以及當數據發生改變的時候vue如何讓界面刷新的?

當我們修改數據的時候vue是通過es5中的Object.defineProperty方法來監聽數據的改變的,當數據發生了改變通過發布訂閱模式統計訂閱者界面發生了刷新,這是一種設計模式。【學習視頻分享:vue視頻教程、web前端視頻】

下圖,從new Vue開始創建Vue實例,會傳入el和data,data會被傳入一個觀察者對象,利用Object.definproperty將data里數據轉化成getter/setter進行數據劫持,data里的每個屬性都會創建一個Dep實例用來保存watcher實例

而el則傳入compile,在compile里進行指令的解析,當解析到el中使用到data里的數據會觸發我們的getter,從而將我們的watcher添加到依賴當中。當數據發生改變的時候會觸發我們的setter發出依賴通知,通知watcher,watcher接受到通知后去向view發出通知,讓view去更新

聊聊Vue中如何實現數據雙向綁定

數據劫持

html部分創建一個id為app的div標簽,里面有span和input標簽,span標簽使用了插值表達式,input標簽使用了v-model

<div class="container" id="app">     <span>內容:{{content}}</span>     <input type="text" v-model="content"> </div>
登錄后復制

js部分引入了一個vue.js文件,實現數據雙向綁定的代碼就寫在這里面,然后創建Vue實例vm,把數據掛載到div標簽上

const vm=new Vue({     el:'#app',         data:{         content:'請輸入開機密碼'     } })
登錄后復制

new了一個Vue實例很明顯需要用到構造函數,在vue的源碼里定義類是使用了function來定義的,這里我使用ES6的class來創建這個Vue實例

然后設置constructor,形參設為obj_instance,作為new一個Vue實例的時候傳入的對象,并把傳進來的對象里的data賦值給實例里的$data屬性

在javascript里對象的屬性發生了變化,需要告訴我們,我們就可以把更改后的屬性更新到dom節點里,因此初始化實例的時候定義一個監聽函數作為調用,調用的時候傳入需要監聽的數據

class Vue{//創建Vue實例   constructor(obj_instance){     this.$data=obj_instance.data     Observer(this.$data)   } } function Observer(data_instance){//監聽函數    }
登錄后復制

打印一下這個實例vm

聊聊Vue中如何實現數據雙向綁定

實例已經創建出來了但是還需要為$data里的每一個屬性進行監聽,要實現數據監聽就用到了Object.definePropertyObject.defineProperty可以修改對象的現有屬性,語法格式為Object.defineProperty(obj, prop, descriptor)

  • obj:要定義屬性的對象
  • prop:要定義或修改的屬性的名稱
  • descriptor:要定義或修改的屬性描述符

監聽對象里的每一個屬性,我們使用Object.keys和foreach遍歷對象里的每一個屬性并且對每一個屬性使用Object.defineProperty進行數據監聽

function Observer(data_instance){   Object.keys(data_instance).forEach(key=>{     Object.defineProperty(data_instance,key,{       enumerable:true,//設置為true表示屬性可以枚舉       configurable:true,//設置為true表示屬性描述符可以被改變       get(){},//訪問該屬性的時候觸發,get和set函數就是數據監聽的核心       set(){},//修改該屬性的時候觸發     })   }) }
登錄后復制

Object.defineProperty前需要將屬性對應的值存起來然后在get函數里面返回出來,不然到了get函數以后屬性的值已經沒了,返回給屬性的值就變成了undefined

let value=data_instance[key] Object.defineProperty(data_instance,key,{   enumerable:true,   configurable:true,   get(){     console.log(key,value);     return value   },   set(){} })
登錄后復制

點擊一下$data里的屬性名就會觸發get函數

聊聊Vue中如何實現數據雙向綁定

然后設置set函數,為set設置形參,這個形參表示新傳進來的屬性值,然后將這個新的屬性值賦值給變量value,不需要return返回什么,只做修改,返回是在訪問get的時候返回的,修改之后get也會訪問最新的value變量值

set(newValue){     console.log(key,value,newValue);     value = newValue }
登錄后復制

聊聊Vue中如何實現數據雙向綁定

但是當前只為$data的第一層屬性設置了get和set,如果還有更深的一層如

obj:{     a:'a',     b:'b' }
登錄后復制

這種的并沒有設置get和set,我們需要一層一層的往屬性里面進行數據劫持,因此使用遞歸再次監聽自己,并在遍歷之前進行條件判斷,沒有子屬性了或者沒有檢測到對象就終止遞歸

function Observer(data_instance){   //遞歸出口   if(!data_instance || typeof data_instance != 'object') return   Object.keys(data_instance).forEach(key=>{     let value=data_instance[key]     Observer(value)//遞歸-子屬性的劫持     Object.defineProperty(data_instance,key,{       enumerable:true,       configurable:true,       get(){         console.log(key,value);         return value       },       set(newValue){         console.log(key,value,newValue);         value = newValue       }     })   }) }
登錄后復制

還有一個細節,如果我們將$data的content屬性從字符串改寫成一個對象,這個新的對象并沒有get和set

聊聊Vue中如何實現數據雙向綁定

因為我們在修改的時候根本沒有設置get和set,因此在set里要調用監聽函數

set(newValue){     console.log(key,value,newValue);     value = newValue     Observer(newValue) }
登錄后復制

聊聊Vue中如何實現數據雙向綁定

模板解析

劫持數據后就要把Vue實例里的數據應用帶頁面上,得要加一個臨時內存區域,將所有數據都更新后再渲染頁面以此減少dom操作

創建一個解析函數,設置2個參數,一個是Vue實例里掛載的元素,另一個是Vue實例,在函數里獲取獲取元素保存在實例了的$el里,獲取元素后放入臨時內存里,需要用到[createDocumentFragment]創建一個新的空白的文檔片段

然后把$el的子節點一個一個加到fragment變量里,頁面已經沒有內容了,內容都被臨時存在fragment里了

class Vue{   constructor(obj_instance){     this.$data=obj_instance.data     Observer(this.$data)     Compile(obj_instance.el,this)   } } function Compile(ele,vm){   vm.$el=document.querySelector(ele)   const fragment=document.createDocumentFragment()   let child;   while (child=vm.$el.firstChild){     fragment.append(child)   }   console.log(fragment);   console.log(fragment.childNodes); }
登錄后復制

聊聊Vue中如何實現數據雙向綁定

現在直接把需要修改的內容應用到文檔碎片里面,應用后重新渲染,只需修改了fragment的childNodes子節點的文本節點,文本節點的類型是3,可以創建一個函數并調用來修改fragment里的內容

節點里面可能還會有節點,因此判定節點類型是否為3,不是就遞歸調用這個解析函數

節點類型為3就進行修改操作,但也不行把整個節點的文本都修改,只需修改插值表達式的內容,因此要使用正則表達式匹配,將匹配的結果保存到變量里,匹配的結果是一個數組,而索引為1的元素才是我們需要提取出來的元素,這個元素就是去除了{{}}和空格得到的字符串,然后就可以直接用Vue實例來訪問對應屬性的值,修改完后return出去結束遞歸

function Compile(ele,vm){   vm.$el=document.querySelector(ele) //獲取元素保存在實例了的$el里   const fragment=document.createDocumentFragment() //創建文檔碎片   let child;   while (child=vm.$el.firstChild){//循環將子節點添加到文檔碎片里     fragment.append(child)   }      fragment_compile(fragment)   function fragment_compile(node){ //修改文本節點內容     const pattern = /{{s*(S*)s*}}/ //檢索字符串中正則表達式的匹配,用于匹配插值表達式     if(node.nodeType===3){       const result = pattern.exec(node.nodeValue)       if(result){         console.log('result[1]')         const value=result[1].split('.').reduce(//split將對象里的屬性分布在數組里,鏈式地進行排列;reduce進行累加,層層遞進獲取$data的值           (total,current)=>total[current],vm.$data         )         node.nodeValue=node.nodeValue.replace(pattern,value) //replace函數將插值表達式替換成$data里的屬性的值       }       return      }     node.childNodes.forEach(child=>fragment_compile(child))   }   vm.$el.appendChild(fragment) //將文檔碎片應用到對應的dom元素里面 }
登錄后復制

頁面的內容又出來了,插值表達式替換成了vm實例里的數據

聊聊Vue中如何實現數據雙向綁定

聊聊Vue中如何實現數據雙向綁定

訂閱發布者模式

雖然進行了數據劫持,和將數據應用到頁面上,但是數據發生變動還不能及時更新,還需要實現訂閱發布者模式

首先創建一個類用來收集和通知訂閱者,生成實例的時候需要有一個數組存放訂閱者的信息,一個將訂閱者添加到這個數組里的方法和一個通知訂閱者的方法,調用這個方法就回去遍歷訂閱者的數組,讓訂閱者調用自身的update方法進行更新

class Dependency{   constructor(){     this.subscribers=[] //存放訂閱者的信息   }   addSub(sub){     this.subscribers.push(sub) //將訂閱者添加到這個數組里   }   notify(){     this.subscribers.forEach(sub=>sub.update()) //遍歷訂閱者的數組,調用自身的update函數進行更新   } }
登錄后復制

設置訂閱者類,需要用到Vue實例上的屬性,需要Vue實例和Vue實例對應的屬性和一個回調函數作為參數,將參數都賦值給實例

然后就可以創建訂閱者的update函數,在函數里調用傳進來的回調函數

class Watcher{   constructor(vm,key,callback){//將參數都賦值給Watcher實例     this.vm=vm     this.key=key     this.callback=callback   }   update(){     this.callback()    } }
登錄后復制

替換文檔碎片內容的時候需要告訴訂閱者如何更新,所以訂閱者實例在模板解析把節點值替換內容的時候創建,傳入vm實例,exec匹配成功后的索引值1和回調函數,將替換文本的執行語句復制到回調函數里,通知訂閱者更新的時候就調用這個回調函數

回調函數里的nodeValue要提前保存,不然替換的內容就不是插值表達式而是替換過的內容

聊聊Vue中如何實現數據雙向綁定

然后就要想辦法將訂閱者存儲到Dependency實例的數組里,我們可以在構造Watcher實例的時候保存實例到訂閱者數組里

Dependency.temp=this //設置一個臨時屬性temp
登錄后復制

將新的訂閱者添加到訂閱者數組里且還要將所有的訂閱者都進行同樣的操作,那么就可以在觸發get的時候將訂閱者添加到訂閱者數組里,為了正確觸發對應的屬性get,需要用reduce方法對key進行同樣的操作

聊聊Vue中如何實現數據雙向綁定

聊聊Vue中如何實現數據雙向綁定

可以看到控制臺打印出了Wathcer實例,每個實例都不同,都對應不同的屬性值

聊聊Vue中如何實現數據雙向綁定

Dependency類還沒創建實例,里面的訂閱者數組是不存在的,所以要先創建實例再將訂閱者添加到訂閱者數組里

聊聊Vue中如何實現數據雙向綁定

聊聊Vue中如何實現數據雙向綁定

修改數據的時候通知訂閱者來進行更新,在set里調用dependency的通知方法,通知方法就會去遍數組,訂閱者執行自己的update方法進行數據更新

聊聊Vue中如何實現數據雙向綁定

但是update調用回調函數缺少設定形參,依舊使用split和reduce方法獲取屬性值

update(){     const value =this.key.split('.').reduce(         (total,current)=>total[current],this.vm.$data     )     this.callback(value) }
登錄后復制

在控制臺修改屬性值都修改成功了,頁面也自動更新了

聊聊Vue中如何實現數據雙向綁定

完成了文本的綁定就可以綁定輸入框了,在vue里通過v-model進行綁定,因此要判斷哪個節點有v-model,元素節點的類型是1,可以使用nodeName來匹配input元素,直接在判斷文本節點下面進行新的判斷

if(node.nodeType===1&&node.nodeName==='INPUT'){     const attr=Array.from(node.attributes)     console.log(attr); }
登錄后復制

節點名字nodeName為v-model,nodeValue為name,就是數據里的屬性名

聊聊Vue中如何實現數據雙向綁定

因此對這個數組進行遍歷,匹配到了v-model根據nodeValue找到對應的屬性值,把屬性值賦值到節點上,同時為了在數據更新后訂閱者知道更新自己,也要在INPUT節點里新增Watcher實例

attr.forEach(i=>{     if(i.nodeName==='v-model'){         const value=i.nodeValue.split('.').reduce(             (total,current)=>total[current],vm.$data         )         node.value=value         new Watcher(vm,i.nodeValue,newValue=>{             node.value=newValue         })     } })
登錄后復制

修改屬性值,頁面也作出修改

聊聊Vue中如何實現數據雙向綁定

最后剩下用視圖改變數據,在v-model的節點上使用addEventListener增加input監聽事件就行了

node.addEventListener('input',e=>{     const arr1=i.nodeValue.split('.')     const arr2=arr1.slice(0,arr1.length - 1)     const final=arr2.reduce(         (total,current)=>total[current],vm.$data     )     final[arr1[arr1.length - 1]]=e.target.value })
登錄后復制

聊聊Vue中如何實現數據雙向綁定

(學習視頻分享:web前端開發、編程基礎視頻)

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
日本高清无卡码一区二区| 人妻三级日本香港三级极97| 免费看片A级毛片免费看| 欧美人与牲动交XXXⅩ| 日韩精品人妻一区二区三区| 图片区小说区另类春色| 亚洲AV永久青草无码精品| 亚洲一线产区二线产区区别在| 越南少妇毛茸茸的大BBW| 97精品国产手机| 啊轻点灬大JI巴太粗熟妇| 国产AV无码区亚洲| 孩教小UXXXⅩ精品| 老司机67194精品线观看| 热RE99久久6国产精品免费| 天堂BT种子在线最新版资源| 亚洲狠狠婷婷综合久久蜜芽| 在C点用力把桌腿A抬离地面时游| ZOOM与人性ZOOM| 国产精品亚洲污污网站入口 | 洗澡被公强奷30分钟视频| 亚洲日韩AV一区二区三区中文| 9420高清完整版在线观看| 公交车舒婷1一20全文| 娇妻初尝粗大滋味借种韩国电影| 妺妺窝人体色WWW网| 色综合天天天天综合狠狠爱| 亚洲国产精品无码第一区二区三区| 中文字幕亚洲无线码在线一区| 成人无码视频免费播放| 激情综合一区二区迷情校园| 欧美黑人成人www在线观看| 无码人妻丰满热妇又大又粗 | 亚洲成a人蜜臀AV在线播放| 中文字幕亚洲综合久久2020| 各种少妇正面着BBW撒尿视频| 精品深夜AV无码一区二区| 人和畜禽CROPROATION| 亚洲AV午夜成人片动漫番| 9色国产深夜内射| 国产熟妇人妻ⅩXXXX麻豆网址| 免费观看电视在线高清| 无码A∨高潮抽搐流白浆8MAV| 曰批免费视频免费无码软件 | 综合偷自拍亚洲乱中文字幕| 国产JJIZZ女人多水喷水| 久久久久国产综合AV天堂| 日日婷婷夜日日天干| 亚洲日韩一区二区一无码| 成人影院YY111111在线观| 久久AV高潮AV无码AV| 日韩午夜理论片 中文字幕| 亚洲日韩国产精品无码AV| 第一次爱的人免费观看电视剧| 久久精品国产成人| 色综合久久久久综合体桃花网| 一二三四视频中文字幕| 国产精品麻豆欧美日韩WW| 内射后入在线观看一区| 亚洲AV无码一区东京热久久| WWW夜片内射视频在观看视频 | 女生裙子里面到底穿了啥| 亚洲AV成人无码影视网| YYYY11111少妇影院| 久久国产精品99精品国产| 天天看高清影视在线观看| 69ZXX少妇内射无码| 黑人巨茎迎战白嫩少妇| 日韩精品无码观看视频免费| 一二三四视频中文字幕| 国产午夜无码视频在线观看| 日本极品人妻VIDEOSSEX| 影帝隔着内裤滑进去了H| 国产精品亚洲ΑV天堂无码| 欧美综合在线激情专区| 亚洲综合网站精品一区二区| 国产精品人人妻人色五月| 人妻少妇(11一32)章| 又粗又大内射免费视频小说| 国精品人妻无码一区免费视频电影| 日本亚欧乱色视频免费观看| 中国无码人妻丰满熟妇啪啪软件 | 亚洲精品一品区二品区三品区| 国产Gay男同gv网站播放免费| 欧美成人精品A∨在线观看| 亚洲色无码国产精品网站可下载| 国产精品一线二线三线有什么区别| 人人爽人人澡人人人妻、百度| 中国少妇精品久久久久无码AV| 狠狠狠的在啪线香蕉WWW、WL| 天堂AV旡码AV毛片毛片免费| 扒开校花的粉嫩小泬| 免费黄色网站久久精品| 亚洲婷婷综合色高清在线| 国产亚洲欧美在线专区| 婷婷五月深深久久精品| 成人精品无码一区二区三区| 欧美白人最猛性XXXXX69交| 伊伊人成亚洲综合人网香| 精品国产三级A∨在线无码| 午夜性又黄又爽免费看尤物| 国产69精品久久久久成人小说| 人妻夜夜爽天天爽三区| 99久久国产综合精品女同图片| 久久久精品人妻久久影视| 亚洲AV毛片成人精品| 国产精品丝袜高跟鞋| 少妇一级无码精品| 成人无码免费一区二区三区 | 亚洲 日本 欧美 中文幕| 国产精品 精品国内自产拍 | 男JI大巴进入女人的视频| 一区二区清无吗视频| 精品综合久久久久久98| 亚洲久热无码中文字幕人妖 | 亚洲成AV人片高潮喷水| 国产无遮挡裸体美女视频| 无人区码一码二码三码区| 国产精品久久久久AV| 天美传媒MV免费观看软件特色 | 无人区一码一码二码三码区别| 给丰满少妇按摩到高潮| 少妇扒开粉嫩小泬视频| 二虎进入温如玉160章小说| 日韩久久久久久中文人妻 | 入禽太深免费视频| 厨房掀起裙子从后面进去视频| 日本无人区码一二三区别| 成人乱码一区二区三区AV| 日韩精品一区二区午夜成人版| 不卡AV电影在线| 色噜噜狠狠色综合成人网| 俄罗斯美女做爰XXXⅩ啪啪 | 公侵犯人妻一区二区三区| 深田えいみ禁欲后被隔壁人妻| 国产99在线 | 免费| 无码国产69精品久久久久孕妇| 国产精品久久久久久妇女| 亚洲 欧美 国产 制服 动漫| 国产色无码精品视频国产| 亚洲AV中文无码字幕色| 精品无码人妻夜人多侵犯18| 亚洲伊人成无码综合影院| 美女裸体无遮挡永久免费视频AP | 超鹏97国语在线| 四虎库影必出精品8848| 国产免费久久久久久无码| 亚洲AV永久无码精品主页| 久久不见久久见免费视频3| 越南女子杂交内射BBWXZ| 欧美巨大黑人精品一二三| 成人无码黄动漫在线播放| 玩弄老太太的BB| 护士高潮喷水白浆| 在教室伦流澡到高潮HGL动漫| 欧美成人精品高清在线播放 | 精品久久久久香蕉网| 在线观看无码AV网站永久| 强行挺进美艳老师的后臀| 跪趴式啪啪GIF动态图27报| 午夜一区欧美二区高清三区| 久久99精品国产99久久6| 中文字字幕在线乱码| 日韩无码av一区二区| 国产亚洲无日韩乱码| 一本久久A久久精品亚洲| 欧美精品亚洲精品日韩传电影 | 久久九九兔免费精品6| 99精产国品一二三产区区别电影| 日韩少妇白浆无码系列| 国产精品亚洲А∨天堂免下载| 亚洲日本中文字幕乱码在线| 男人扒开添女人下部免费视频| 国99精品无码一区二区三区| 亚洲成人综合av| 女生输了给对方玩一个月| 国产成人AV一区二区三区在线观| 亚洲国产不卡久久久久久| 男人边做边吃奶头视频| 国产成人精品无码A区在线观看| 亚洲国产精品特色大片观看完整版| 么公的好大好硬好深好爽视频| 成人区人妻精品一区二| 亚洲AV午夜精品一区二区三区| 免费日韩无人区码卡二卡3卡 | 四虎影视1304T| 久久九九久精品国产综合一千收藏 | 亚洲国产精品特色大片观看完整版| 免费乱码人妻系列无码专区| 国产白嫩漂亮美女在线观看| 亚洲中文字幕波多野结衣| 日本一品和二品区别| 狠狠亚洲婷婷综合色香五月| CHINA熟妇老熟女HD| 小洁和公H文翁17| 嫩草伊人久久精品少妇AV| 国产精品午夜无码AV体验区| 欲色欲色天天天WWW| 污污内射久久一区二区欧美日韩| 麻花传媒剧国产MV高清播放|