电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

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

Vue 的雙向綁定原理與用法揭秘

瀏覽:2日期:2023-01-23 08:46:20

本文實(shí)例講述了Vue 的雙向綁定原理與用法。分享給大家供大家參考,具體如下:

Vue 中需要輸入什么內(nèi)容的時(shí)候,自然會(huì)想到使用 <input v-model='xxx' /> 的方式來(lái)實(shí)現(xiàn)雙向綁定。下面是一個(gè)最簡(jiǎn)單的示例

<div id='app'> <h2>What’s your name:</h2> <input v-model='name' /> <div>Hello {{ name }}</div></div>

new Vue({ el: '#app', data: { name: '' }});

在這個(gè)示例的輸入框中輸入的內(nèi)容,會(huì)隨后呈現(xiàn)出來(lái)。這是 Vue 原生對(duì) <input> 的良好支持,也是一個(gè)父組件和子組件之間進(jìn)行雙向數(shù)據(jù)傳遞的典型示例。不過(guò) v-model 是 Vue 2.2.0 才加入的一個(gè)新功能,在此之前,Vue 只支持單向數(shù)據(jù)流。

Vue 的單向數(shù)據(jù)流

Vue 的單向數(shù)據(jù)流和 React 相似,父組件可以通過(guò)設(shè)置子組件的屬性(Props)來(lái)向子組件傳遞數(shù)據(jù),而父組件想獲得子組件的數(shù)據(jù),得向子組件注冊(cè)事件,在子組件高興的時(shí)候觸發(fā)這個(gè)事件把數(shù)據(jù)傳遞出來(lái)。一句話總結(jié)起來(lái)就是,Props 向下傳遞數(shù)據(jù),事件向上傳遞數(shù)據(jù)。

上面那個(gè)例子,如果不使用 v-model,它應(yīng)該是這樣的

<input :value='name' @input='name = $event.target.value' />

由于事件處理寫成了內(nèi)聯(lián)模式,所以腳本部分不需要修改。但是多數(shù)情況下,事件一般都會(huì)定義成一個(gè)方法,代碼就會(huì)復(fù)雜得多

<input :value='name' @input='updateName' />

new Vue({ // .... methods: { updateName(e) { this.name = e.target.value; } }})

從上面的示例來(lái)看 v-model 節(jié)約了不少代碼,最重要的是可以少定義一個(gè)事件處理函數(shù)。所以 v-model 實(shí)際干的事件包括

使用 v-bind(即 :)單向綁定一個(gè)屬性(示例::value='name') 綁定 input 事件(即 @input)到一個(gè)默認(rèn)實(shí)現(xiàn)的事件處理函數(shù)(示例:@input=updateName 這個(gè)默認(rèn)的事件處理函數(shù)會(huì)根據(jù)事件對(duì)象帶入的值來(lái)修改被綁定的數(shù)據(jù)(示例:this.name = e.target.value)自定義組件的 v-model

Vue 對(duì)原生組件進(jìn)行了封裝,所以 <input> 在輸入的時(shí)候會(huì)觸發(fā) input 事件。但是自定義組件應(yīng)該怎么呢?這里不妨借助 JsFiddle Vue 樣板的 Todo List 示例。

JsFiddle 的 Vue 樣板點(diǎn)擊 JsFilddle 的 Logo,在上面彈出面板中選擇 Vue 樣板即可

樣板代碼包含 HTML 和 Vue(js) 兩個(gè)部分,代碼如下:

<div id='app'> <h2>Todos:</h2> <ol> <li v-for='todo in todos'> <label> <input type='checkbox' v-on:change='toggle(todo)' v-bind:checked='todo.done'> <del v-if='todo.done'> {{ todo.text }} </del> <span v-else> {{ todo.text }} </span> </label> </li> </ol></div>

new Vue({ el: '#app', data: { todos: [ { text: 'Learn JavaScript', done: false }, { text: 'Learn Vue', done: false }, { text: 'Play around in JSFiddle', done: true }, { text: 'Build something awesome', done: true } ] }, methods: { toggle: function(todo){ todo.done = !todo.done } }})定義 Todo 組件

JsFiddle 的 Vue 模板默認(rèn)實(shí)現(xiàn)一個(gè) Todo 列表的展示,數(shù)據(jù)是固定的,所有內(nèi)容在一個(gè)模板中完成。我們首先要做事情是把單個(gè) Todo 改成一個(gè)子組件。因?yàn)樵?JsFiddle 中不能寫成多文件的形式,所以組件使用 Vue.component() 在腳本中定義,主要是把 <li> 內(nèi)容中的那部分拎出來(lái):

Vue.component('todo', { template: `<label> <input type='checkbox' @change='toggle' :checked='isDone'> <del v-if='isDone'> {{ text }} </del> <span v-else> {{ text }} </span></label>`, props: ['text', 'done'], data() { return { isDone: this.done }; }, methods: { toggle() { this.isDone = !this.isDone; } }});

原來(lái)定義在 App 中的 toggle() 方法也稍作改動(dòng),定義在組件內(nèi)了。toggle() 調(diào)用的時(shí)候會(huì)修改表示是否完成的 done 的值。但由于 done 是定義在 props 中的屬性,不能直接賦值,所以采用了官方推薦的第一種方法,定義一個(gè)數(shù)據(jù) isDone,初始化為 this.done,并在組件內(nèi)使用 isDone 來(lái)控制是否完成這一狀態(tài)。

相應(yīng)的 App 部分的模板和代碼精減了不少:

<div id='app'> <h2>Todos:</h2> <ol> <li v-for='todo in todos'> <todo :text='todo.text' :done='todo.done'></todo> </li> </ol></div>

new Vue({ el: '#app', data: { todos: [ { text: 'Learn JavaScript', done: false }, { text: 'Learn Vue', done: false }, { text: 'Play around in JSFiddle', done: true }, { text: 'Build something awesome', done: true } ] }});

不過(guò)到此為止,數(shù)據(jù)仍然是單向的。從效果上來(lái)看,點(diǎn)擊復(fù)選框可以反饋出刪除線線效果,但這些動(dòng)態(tài)變化都是在 todo 組件內(nèi)部完成的,不存在數(shù)據(jù)綁定的問(wèn)題。

為 Todo List 添加計(jì)數(shù)

為了讓 todo 組件內(nèi)部的狀態(tài)變化能在 Todo List 中呈現(xiàn)出來(lái),我們?cè)?Todo List 中添加計(jì)數(shù),展示已經(jīng)完成的 Todo 數(shù)量。因?yàn)檫@個(gè)數(shù)量受 todo 組件內(nèi)部狀態(tài)(數(shù)據(jù))的影響,這就需要將 todo 內(nèi)部數(shù)據(jù)變化反應(yīng)到其父組件中,這才有 v-model 的用武之地。

這個(gè)數(shù)量我們?cè)跇?biāo)題中以 n/m 的形式呈現(xiàn),比如 2/4 表示一共 4 條 Todo,已經(jīng)完成 2 條。這需要對(duì) Todo List 的模板和代碼部分進(jìn)行修改,添加 countDone 和 count 兩個(gè)計(jì)算屬性:

<div id='app'> <h2>Todos ({{ countDone }}/{{ count }}):</h2> <!-- ... --></div>

new Vue({ // ... computed: { count() { return this.todos.length; }, countDone() { return this.todos.filter(todo => todo.done).length; } }});

現(xiàn)在計(jì)數(shù)呈現(xiàn)出來(lái)了,但是現(xiàn)在改變?nèi)蝿?wù)狀態(tài)并不會(huì)對(duì)這個(gè)計(jì)數(shù)產(chǎn)生影響。我們要讓子組件的變動(dòng)對(duì)父組件的數(shù)據(jù)產(chǎn)生影響。v-model 待會(huì)兒再說(shuō),先用最常見(jiàn)的方法,事件:

子組件 todo 在 toggle() 中觸發(fā) toggle 事件并將 isDone 作為事件參數(shù) 父組件為子組件的 toggle 事件定義事件處理函數(shù)

Vue.component('todo', { //... methods: { toggle(e) { this.isDone = !this.isDone; this.$emit('toggle', this.isDone); } }});

<!-- #app 中其它代碼略 --><todo :text='todo.text' :done='todo.done' @toggle='todo.done = $event'></todo>

這里為 @toggle 綁定的是一個(gè)表達(dá)式。因?yàn)檫@里的 todo 是一個(gè)臨時(shí)變量,如果在 methods 中定義專門的事件處理函數(shù)很難將這個(gè)臨時(shí)變量綁定過(guò)去(當(dāng)然定義普通方法通過(guò)調(diào)用的形式是可以實(shí)現(xiàn)的)。

事件處理函數(shù),一般直接對(duì)應(yīng)于要處理的事情,比如定義 onToggle(e),綁定為 @toggle='onToggle'。這種情況下不能傳入 todo 作為參數(shù)。

普通方法,可以定義成 toggle(todo, e),在事件定義中以函數(shù)調(diào)用表達(dá)式的形式調(diào)用:@toggle='toggle(todo, $event)'。它和 todo.done = $event` 同屬表達(dá)式。

注意二者的區(qū)別,前者是綁定的處理函數(shù)(引用),后者是綁定的表達(dá)式(調(diào)用)

現(xiàn)在通過(guò)事件方式已經(jīng)達(dá)到了預(yù)期效果

改造成 v-model

之前我們說(shuō)了要用 v-model 實(shí)現(xiàn)的,現(xiàn)在來(lái)改造一下。注意實(shí)現(xiàn) v-model 的幾個(gè)要素

子組件通過(guò) value 屬性(Prop)接受輸入 子組件通過(guò)觸發(fā) input 事件輸出,帶數(shù)組參數(shù) 父組件中用 v-model 綁定

Vue.component('todo', { // ... props: ['text', 'value'], // <-- 注意 done 改成了 value data() { return { isDone: this.value // <-- 注意 this.done 改成了 this.value }; }, methods: { toggle(e) { this.isDone = !this.isDone; this.$emit('input', this.isDone); // <-- 注意事件名稱變了 } }});

<!-- #app 中其它代碼略 --><todo :text='todo.text' v-model='todo.done'></todo>.sync 實(shí)現(xiàn)其它數(shù)據(jù)綁定

前面講到了 Vue 2.2.0 引入 v-model 特性。由于某些原因,它的輸入屬性是 value,但輸出事件叫 input。v-model、value、input 這三個(gè)名稱從字面上看不到半點(diǎn)關(guān)系。雖然這看起來(lái)有點(diǎn)奇葩,但這不是重點(diǎn),重點(diǎn)是一個(gè)控件只能雙向綁定一個(gè)屬性嗎?

Vue 2.3.0 引入了 .sync 修飾語(yǔ)用于修飾 v-bind(即 :),使之成為雙向綁定。這同樣是語(yǔ)法糖,添加了 .sync 修飾的數(shù)據(jù)綁定會(huì)像 v-model 一樣自動(dòng)注冊(cè)事件處理函數(shù)來(lái)對(duì)被綁定的數(shù)據(jù)進(jìn)行賦值。這種方式同樣要求子組件觸發(fā)特定的事件。不過(guò)這個(gè)事件的名稱好歹和綁定屬性名有點(diǎn)關(guān)系,是在綁定屬性名前添加 update: 前綴。

比如 <sub :some.sync='any' /> 將子組件的 some 屬性與父組件的 any 數(shù)據(jù)綁定起來(lái),子組件中需要通過(guò) $emit('update:some', value) 來(lái)觸發(fā)變更。

上面的示例中,使用 v-model 綁定始終感覺(jué)有點(diǎn)別扭,因?yàn)?v-model 的字面意義是雙向綁定一個(gè)數(shù)值,而表示是否未完成的 done 其實(shí)是一個(gè)狀態(tài),而不是一個(gè)數(shù)值。所以我們?cè)俅螌?duì)其進(jìn)行修改,仍然使用 done 這個(gè)屬性名稱(而不是 value),通過(guò) .sync 來(lái)實(shí)現(xiàn)雙向綁定。

Vue.component('todo', { // ... props: ['text', 'done'], // <-- 恢復(fù)成 done data() { return { isDone: this.done // <-- 恢復(fù)成 done }; }, methods: { toggle(e) { this.isDone = !this.isDone; this.$emit('update:done', this.isDone); // <-- 事件名稱:update:done } }});

<!-- #app 中其它代碼略 --><!-- 注意 v-model 變成了 :done.sync,別忘了冒號(hào)喲 --><todo :text='todo.text' :done.sync='todo.done'></todo>揭密 Vue 雙向綁定

通過(guò)上面的講述,我想大家應(yīng)該已經(jīng)明白了 Vue 的雙向綁定其實(shí)就是普通單向綁定和事件組合來(lái)完成的,只不過(guò)通過(guò) v-model 和 .sync 注冊(cè)了默認(rèn)的處理函數(shù)來(lái)更新數(shù)據(jù)。Vue 源碼中有這么一段

// @file: src/compiler/parser/index.jsif (modifiers.sync) { addHandler( el, `update:${camelize(name)}`, genAssignmentCode(value, `$event`) )}

從這段代碼可以看出來(lái),.sync 雙向綁定的時(shí)候,編譯器會(huì)添加一個(gè) update:${camelize(name)} 的事件處理函數(shù)來(lái)對(duì)數(shù)據(jù)進(jìn)行賦值(genAssignmentCode 的字面意思是生成賦值的代碼)。

展望

目前 Vue 的雙向綁定還需要通過(guò)觸發(fā)事件來(lái)實(shí)現(xiàn)數(shù)據(jù)回傳。這和很多所的期望的賦值回傳還是有一定的差距。造成這一差距的主要原因有兩個(gè)

需要通過(guò)事件回傳數(shù)據(jù) 屬性(prop)不可賦值

在現(xiàn)在的 Vue 版本中,可以通過(guò)定義計(jì)算屬性來(lái)實(shí)現(xiàn)簡(jiǎn)化,比如

computed: { isDone: { get() { return this.done; }, set(value) { this.$emit('update:done', value); } }}

說(shuō)實(shí)在的,要多定義一個(gè)意義相同名稱不同的變量名也是挺費(fèi)腦筋的。希望 Vue 在將來(lái)的版本中可以通過(guò)一定的技術(shù)手段減化這一過(guò)程,比如為屬性(Prop)聲明添加 sync 選項(xiàng),只要聲明 sync: true 的都可以直接賦值并自動(dòng)觸發(fā) update:xxx 事件。

當(dāng)然作為一個(gè)框架,在解決一個(gè)問(wèn)題的時(shí)候,還要考慮對(duì)其它特性的影響,以及框架的擴(kuò)展性等問(wèn)題,所以最終雙向綁定會(huì)演進(jìn)成什么樣子,我們對(duì) Vue 3.0 拭目以待。

感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運(yùn)行工具:http://tools.jb51.net/code/HtmlJsRun測(cè)試上述代碼運(yùn)行效果。

希望本文所述對(duì)大家vue.js程序設(shè)計(jì)有所幫助。

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 电池挤压试验机-自行车喷淋-车辆碾压试验装置-深圳德迈盛测控设备有限公司 | 北京中航时代-耐电压击穿试验仪厂家-电压击穿试验机 | 西安烟道厂家_排气道厂家_包立管厂家「陕西西安」推荐西安天宇烟道 | 北钻固控设备|石油钻采设备-石油固控设备厂家| 青岛球场围网,青岛车间隔离网,青岛机器人围栏,青岛水源地围网,青岛围网,青岛隔离栅-青岛晟腾金属制品有限公司 | 三佳互联一站式网站建设服务|网站开发|网站设计|网站搭建服务商 赛默飞Thermo veritiproPCR仪|ProFlex3 x 32PCR系统|Countess3细胞计数仪|371|3111二氧化碳培养箱|Mirco17R|Mirco21R离心机|仟诺生物 | 干粉砂浆设备-干粉砂浆生产线-干混-石膏-保温砂浆设备生产线-腻子粉设备厂家-国恒机械 | TPE塑胶原料-PPA|杜邦pom工程塑料、PPSU|PCTG材料、PC/PBT价格-悦诚塑胶 | 热镀锌槽钢|角钢|工字钢|圆钢|H型钢|扁钢|花纹板-天津千百顺钢铁贸易有限公司 | 微波萃取合成仪-电热消解器价格-北京安合美诚科学仪器有限公司 | 组织研磨机-高通量组织研磨仪-实验室多样品组织研磨机-东方天净 传递窗_超净|洁净工作台_高效过滤器-传递窗厂家广州梓净公司 | 山东螺杆空压机,烟台空压机,烟台开山空压机-烟台开山机电设备有限公司 | 活动策划,舞台搭建,活动策划公司-首选美湖上海活动策划公司 | 福建成考网-福建成人高考网| 斗式提升机,斗式提升机厂家-淄博宏建机械有限公司 | 全自动面膜机_面膜折叠机价格_面膜灌装机定制_高速折棉机厂家-深圳市益豪科技有限公司 | 月嫂_保姆_育婴_催乳_母婴护理_产后康复_养老护理-吉祥到家家政 硫酸亚铁-聚合硫酸铁-除氟除磷剂-复合碳源-污水处理药剂厂家—长隆科技 | 黑龙江京科脑康医院-哈尔滨精神病医院哪家好_哈尔滨精神科医院排名_黑龙江精神心理病专科医院 | 生态板-实木生态板-生态板厂家-源木原作生态板品牌-深圳市方舟木业有限公司 | 苏州防水公司_厂房屋面外墙防水_地下室卫生间防水堵漏-苏州伊诺尔防水工程有限公司 | 水冷式工业冷水机组_风冷式工业冷水机_水冷螺杆冷冻机组-深圳市普威机械设备有限公司 | 安平县鑫川金属丝网制品有限公司,防风抑尘网,单峰防风抑尘,不锈钢防风抑尘网,铝板防风抑尘网,镀铝锌防风抑尘网 | 河南中整光饰机械有限公司-抛光机,去毛刺抛光机,精密镜面抛光机,全自动抛光机械设备 | 酵素生产厂家_酵素OEM_酵素加盟_酵素ODM_酵素原料厂家_厦门益力康 | 红外光谱仪维修_二手红外光谱仪_红外压片机_红外附件-天津博精仪器 | 猪I型/II型胶原-五克隆合剂-细胞冻存培养基-北京博蕾德科技发展有限公司 | 光谱仪_积分球_分布光度计_灯具检测生产厂家_杭州松朗光电【官网】 | 卫生型双针压力表-高温防腐差压表-安徽康泰电气有限公司 | 屏蔽服(500kv-超高压-特高压-电磁)-徐吉电气| 365文案网_全网创意文案句子素材站| 两头忙,井下装载机,伸缩臂装载机,30装载机/铲车,50装载机/铲车厂家_价格-莱州巨浪机械有限公司 | led太阳能路灯厂家价格_风光互补庭院灯_农村市政工程路灯-中山华可路灯品牌 | 烟雾净化器-滤筒除尘器-防爆除尘器-除尘器厂家-东莞执信环保科技有限公司 | 小型气象站_车载气象站_便携气象站-山东风途物联网 | 成都APP开发-成都App定制-成都app开发公司-【未来久】 | 检验科改造施工_DSA手术室净化_导管室装修_成都特殊科室建设厂家_医疗净化工程公司_四川华锐 | 硅PU球场、篮球场地面施工「水性、环保、弹性」硅PU材料生产厂家-广东中星体育公司 | 卫生纸复卷机|抽纸机|卫生纸加工设备|做卫生纸机器|小型卫生纸加工需要什么设备|卫生纸机器设备多少钱一台|许昌恒源纸品机械有限公司 | 绿萝净除甲醛|深圳除甲醛公司|测甲醛怎么收费|培训机构|电影院|办公室|车内|室内除甲醛案例|原理|方法|价格立马咨询 | 生物除臭剂-除味剂-植物-污水除臭剂厂家-携葵环保有限公司 | 工业硝酸钠,硝酸钠厂家-淄博「文海工贸」|