v-model
是 Vue 中一個常用的指令,常用於表單中的數據綁定。如下基本用法想必大家都很熟悉,data 中的 checked 屬性的值就會隨着多選框的狀態實時變化。
<el-checkbox v-model="checked" />
但你或許聽說過,Vue 組件之間是“單向數據流”,即通過 props
從父組件向子組件單向傳遞數據。那么,v-model 的“雙向綁定”效果是如何實現的呢?
自定義組件實現 v-model
首先來看一個實際應用的例子,需求如下:在創建試卷頁面 paperCreate
中,通過選擇題目組件 questionSelect
查詢並選擇題目組成試卷,效果如下圖所示。
為了方便使用,希望能在選擇題目組件上使用 v-model 指令進行雙向綁定:
<!-- 選擇題目組件 -->
<question-select v-model="formData.questions" />
<!-- 顯示已選擇題目 -->
<div v-for="item in formData.questions" :key="item.id" >
<question :question="item" />
</div>
value 屬性和 input 事件
自定義支持 v-model 的組件只需要滿足兩個條件:
- value 屬性作為傳入數據
- 數據改變時,將新數據作為 payload,向上 emit 一個 input 事件
就是這么簡單,相關代碼為:
export default {
props: {
value: Array, // 類型根據實際需要
},
methods: {
handelChange() {
this.$emit("input", newValue);
},
},
};
如果不想使用默認的 value 屬性和 input 事件,也可以通過 model 對象自定義相應屬性和事件:
model: {
prop: 'checked',
event: 'change',
},
單向數據流
需要注意的是,prop 傳值是單向的,即父組件中的數據改變會反映到子組件中,但在子組件內部不能主動改變 prop 的值。具體來說就是,子組件中不能使用類似於 v-model="value"
之類試圖改變 value 值的操作。
因此表格中的 checkbox,也只單向傳入 value 來控制是否選中的狀態,然后在選中狀態改變時手動處理改變后的結果。
- 對於表格中的一行(即一道題目),如果傳入的 value 數組(即已選中的題目列表)中包含它的 id,則顯示為選中狀態
- 不能直接改變原數組 value,直接構造新列表傳出:
- 如果新增了一個選項,傳原列表 + 所選對象
- 如果取消了一個選項,傳原列表 - 所選對象
(PS:組件庫中提供的 el-checkbox 實際上也是另一個自定義組件,可以同理分析)
<el-table :data="questionList">
<el-table-column>
<template slot-scope="scope">
<el-checkbox
:value="selectedIds.includes(scope.row.id)"
@change="(value) => handelChange(scope.row, value)"
/>
</template>
</el-table-column>
<!-- 其他屬性 -->
</el-table>
props: {
value: Array,
},
computed: {
selectedIds() {
return this.value.map((item) => item.id);
},
},
methods: {
handelChange(item, checked) {
if (checked) {
this.$emit("input", [...this.value, item]);
} else {
this.$emit(
"input",
this.value.filter((element) => element.id != item.id)
);
}
},
},
具體寫法與組件庫的具體實現有關,簡單說明一下此處的 element 語法:
- scope.row 為 el-table 表格當前行對應的對象
- el-checkbox 的 change 事件的負載為復選框點擊后的新值
然后就結束了,父組件使用選擇題目組件時就能正常使用 v-model 了。本例中綁定的數據是完整的題目列表,原因是需要在頁面中顯示已選擇題目的具體信息;如果只需要 id 數據(例如 select 那樣的組件),則 emit 時只傳 id 列表即可,寫法完全一致。
雙向綁定
通過上面的例子想必你已經看出來了,v-model 指令的“雙向綁定”實際上是一個語法糖:它將父組件的數據通過 prop 傳入子組件,再監聽子組件的輸入事件來更新父組件中的數據,從而實現雙向綁定的效果。
結語&參考資料
以上是個人對 Vue 中 v-model 指令的一些理解與思考,希望能給你提供幫助。如果有問題或疏漏之處,歡迎在評論中討論與指正。
我將繼續在個人博客中更新自己的學習筆記,以前端技術(Vue框架)為主,感興趣的話歡迎關注!
參考資料:Vue 官方文檔