您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Vue中不通過v-model怎么實現雙向綁定”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Vue中不通過v-model怎么實現雙向綁定”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
先來看解答:
<template> <div class="test-v-model"> <p>使用v-model</p> <input v-model="msg" placeholder="edit me" /> <p>{{ msg }}</p> <p>不使用v-model</p> <input :value="msg1" @input="handleInput" placeholder="edit me" /> <p>{{ msg1 }}</p> </div> </template> <script> export default { name: 'test-v-model', data() { return { msg: '', msg1: '' } }, methods: { handleInput(e) { this.msg1 = e.target.value } } } </script>
不使用 v-model,就需要通過 value 屬性綁定值和 input 事件改變綁定值來實現雙向綁定。
換句話說,v-model只是一種簡寫形式而已
事實上,v-model 的本質就是語法糖,它負責監聽用戶的輸入事件以更新數據,并對一些極端場景進行一些特殊處理。 -- 官方文檔
v-model 在內部為不同的輸入元素使用不同的 property 并拋出不同的事件:
text 和 textarea 元素使用
value
property 和input
事件;checkbox 和 radio 使用
checked
property 和change
事件;select 字段將
value
作為 prop 并將change
作為事件。
雙向綁定
單向數據綁定
vue 組件之間交互的單向數據流
問:什么是雙向綁定?
雙向綁定就是當數據變化之后,視圖同步更新,當視圖變化之后,數據也會更新。
問:什么是單向數據綁定?
單向數據綁定就是當數據變化之后,視圖同步更新,當視圖變化之后,數據不會更新。
在vue中是通過指令 v-model 來實現雙向綁定,通過 v-bind
來實現單向數據綁定
看完下面這段代碼和這段代碼運行的gif演示,你就能明白他們的區別了。
<template> <div> <p>雙向綁定</p> <input v-model="msg" placeholder="edit me" /> <p>{{ msg }}</p> <p>單向數據綁定</p> <input v-bind:value="msg1" placeholder="edit me" /> <p>{{ msg1 }}</p> </div> </template> <script> export default { name: 'test-v-model', data() { return { msg: '', msg1: '' } } } </script>
從gif圖中可以看出,使用 v-model,當數據變化之后,視圖同步更新,當視圖變化之后,數據也會更新,這就是雙向綁定。
使用 v-bind,當數據變化之后,視圖同步更新,當視圖變化之后,數據不會更新,這就是單向數據綁定。
問:什么是 vue 單向數據流?
子組件不能改變父組件傳遞給它的 prop 屬性,推薦的做法是它拋出事件,通知父組件自行改變綁定的值。
總結起來就是數據向下,事件向上。
vue 文檔在介紹 Prop 時就提出了單向數據流的概念,點擊此處 查看 vue 文檔對單向數據流的說明。
所有的 prop 都使得其父子 prop 之間形成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,但是反過來則不行。這樣會防止從子組件意外變更父級組件的狀態,從而導致你的應用的數據流向難以理解。
額外的,每次父級組件發生變更時,子組件中所有的 prop 都將會刷新為最新的值。這意味著你不應該在一個子組件內部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制臺中發出警告。
我們看下面這個例子:
子組件直接對 prop 值做雙向綁定,會發生什么?
父組件代碼:
<template> <child-component :value="fatherValue" /> </template> <script> import ChildComponent from './child.vue' export default { name: 'father-component', components: { ChildComponent }, data() { return { fatherValue: '' } } } </script>
子組件代碼:
<template> <div class="child-component"> <input v-model="value" placeholder="edit me" /> <p>{{ value }}</p> </div> </template> <script> export default { name: 'child-component', props: { value: { type: String, default: '' } } } </script>
可以看到,childComponent中的 prop 值可以實現雙向綁定,但是 FatherComponent 中的 data 值并未發生改變,而且控制臺拋出了警告:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
翻譯一下:避免直接改變 prop 值,因為每當父組件重新渲染時,該值將被覆蓋。相反,使用基于 prop 值的 data 或 computed。
很顯然,直接改變子組件的 prop 值的這種行為被 vue 禁止了。
如何操作傳入子組件的 prop 值
但是很多時候,我們確實要操作傳入子組件的 prop 值,該怎么辦呢?
正如上面的警告所說,有兩種辦法:
這個 prop 用來傳遞一個初始值,定義一個本地的 data property 并將這個 prop 用作其初始值
props: { initialCounter: { type: Number, default: 0 }, }, data() { return { counter: this.initialCounter } }
這個 prop 以一種原始的值傳入且需要進行轉換,用這個 prop 的值來定義一個計算屬性
props: { size: { type: String, default: '' } }, computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
這樣不管怎么操作數據都是操作的子組件數據了,不會影響到父組件數據。
所以,我們想用 prop 傳入的數據實現雙向綁定,可以這么寫:
父組件代碼不變
子組件里用 innerValue 來接收傳入的 value :
<template> <div class="child-component"> <input v-model="innerValue" placeholder="edit me" /> <p>{{ innerValue }}</p> </div> </template> <script> export default { name: 'child-component', props: { value: { type: String, default: '' } }, data() { return { innerValue: this.value } } } </script>
這里要注意一個問題
在 JavaScript 中對象和數組是通過引用傳入的,所以對于一個數組或對象類型的 prop 來說,在子組件中改變變更這個對象或數組本身將會影響到父組件的狀態。
還是上面的例子,我們將傳入的值改為對象:
父組件代碼:
<template> <child-component :obj="fatherObj" /> </template> <script> import ChildComponent from './child.vue' export default { name: 'father-component', components: { ChildComponent }, data() { return { fatherObj: { name: 'lin' } } } } </script>
子組件代碼:
<template> <div class="child-component"> <input v-model="innerObj.name" placeholder="edit me" /> <p>{{ innerObj.name }}</p> </div> </template> <script> export default { name: 'child-component', props: { obj: { type: Object, default: () => {} } }, data() { return { innerObj: this.obj } } } </script>
這里的 this.obj
是引用類型,賦值給了 innerObj
,所以 innerObj
實際上還是指向了父組件的數據,對 innerObj.name
的修改依然會影響到父組件
所以,處理這種引用類型數據的時候,需要深拷貝一下
import { clone } from 'xe-utils' export default { name: 'child-component', props: { obj: { type: Object, default: () => {} } }, data() { return { innerObj: clone(this.obj, true) } } }
如上圖所示,這樣子組件和父組件之間的數據就不會互相影響了。
讀到這里,這篇“Vue中不通過v-model怎么實現雙向綁定”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。