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="https://www.cnblogs.com/skuld-yi/archive/2022/01/19/questionList">
<el-table-column>
<template slot-scope="scope">
<el-checkbox
:value="https://www.cnblogs.com/skuld-yi/archive/2022/01/19/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 官方檔案
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/415923.html
標籤:其他
