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 官方文件