之前提到,元件如果要接收資料,必須用 props
元件如果要向外傳資料,則是定義 emit
事件
假設我們的元件有個 <input>
標籤,我們希望元件內部的 <input>
可以跟外部的資料做到雙向綁定,那們根據之前提到的寫法,可能會這樣寫:
const app = Vue.createApp({
setup() {
const message = Vue.ref("hello");
const updateMsg = (val) => {
message = val;
};
return {
message,
updateMsg,
};
},
});
app.component("my-component", {
// :value 把 prop 綁到 input 的 value
// 透過 @input 事件把使用者輸入的資料往外傳
template: `
<input :value="msg"
@input="$emit('update', $event.target.value)"
/>
`,
props: ["msg"],
emits: ["update"],
});
app.mount("#app");
並且模板中需要綁定資料(:msg="message"
),同時宣告事件(@update="updateMsg"
):
<div id="app">
<my-component :msg="message" @update="updateMsg"></my-component>
{{ message }}
</div>
提到表單事件,不得不提 v-model
功能。
上面的需求,Vue 可以讓我們用 v-model
來綁定元件。
如果元件只需要處理一個 v-model
資料綁定,元件的 props 請定義成 modelValue
,emit 則定義成 update:modelValue
。
app.component("my-component", {
template: `
<input :value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
`,
props: ["modelValue"],
emits: ["update:modelValue"],
});
Vue 實體則是寫這個內容,預計要把 message
跟內部表單綁在一起:
const app = Vue.createApp({
setup() {
const message = Vue.ref("hello");
return {
message,
};
},
});
接著在外層使用元件時,就可以直接使用 v-model
把資料傳進去了:
<div id="app">
<my-component v-model="message"></my-component>
{{ message }}
</div>
語法看起來很複雜,但概念其實很單純
就是在外部宣告狀態,讓外部的狀態可以跟「元件內部」的表單綁定。
完整的範例可以到這裡看
剛才的寫法,是元件只有一個表單時,預設使用名稱為 modelValue
的 prop , 與 update:modelValue
的 emit
如果有多個表單需要被綁定外部狀態的話,可以這樣寫
app.component("my-component", {
template: `
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
`,
props: ["firstName", "lastName"],
emits: ["update:firstName", "update:lastName"],
});
外層就可以綁定多個狀態了:
<div id="app">
<h1>{{ first }} {{ last }}</h1>
<my-component v-model:first-name="first" v-model:last-name="last">
</my-component>
</div>
記得要宣告綁定的狀態:
const app = Vue.createApp({
setup() {
const first = Vue.ref("John");
const last = Vue.ref("Doe");
return {
first,
last,
};
},
});
完整的程式碼可以到這裡試試