[Vue] 元件-Emit
TL;DR
參考資料
相關連結
Emit簡介
因為元件之間的資料互相獨立,前面介紹外層元件(父元件)如果要傳遞資料給內層元件(子元件)時,需要使用props
。
相對的,內層元件如果要傳遞資料給外層元件時,則是使用 emit事件。
在傳遞事件時,不一定需要傳送資料。也可以只有觸發事件本身。
-
先定義外層接收的方法
-
定義內層的 $emit 觸發方法
-
使用 v-on 的方式觸發外層方法(口訣:前內、後外)
無參數傳遞
- html(#app)
- vue
<div id="app">
<div class="p-5">
<p>
{{` 外層num數值為: ${num}`}}
</p>
<button-counter
@parent-emit-name="addNum"
>
</button-counter>
</div>
</div>
const app = Vue.createApp({
data() {
return {
num: 0,
};
},
methods: {
addNum() {
console.log('addNum');
this.num++
},
}
});
app.component('button-counter', {
methods: {
childEmitName(){
this.$emit('parentEmitName')
}
},
template: `<button type="button" @click="childEmitName">內層button-counter按鈕</button>`
});
app.mount('#app');
先在methods
內定義一個方法,這邊定義為childEmitName
( Line:18(Vue) )。
接著在 Line:19 定義一個向外傳遞的事件名稱:this.$emit('parentEmitName')
。該名稱可以自訂。
外層元件在接收時根據前內後外的口訣,將內層傳遞出來的事件綁定到外層觸發事件上 Line:7(#app) ,接著再選擇外層要執行的方法為addNum
。
因為html在使用屬性時,必須為小寫。
所以外層元件在觸發內層傳遞出來的事件時,如果名稱有大寫,需要轉換為 - 連接(與綁定style類似)
e.g:
parentEmitName
在使用時為 :parent-emit-name="parentMethod"
有傳遞參數
- html(#app)
- vue
<div id="app">
<div class="p-5">
內部傳來的文字:{{ text }}<br>
<button-text
@emit-text="getData"
class="mt-2"
>
</button-text>
</div>
</div>
const app = Vue.createApp({
data() {
return {
text: ''
};
},
methods: {
getData(text) {
console.log('getData', text);
this.text = text;
}
}
});
app.component('button-text', {
data() {
return {
text: '內部資料',
}
},
methods: {
emit(){
this.$emit('emit-text',this.text)
}
},
template: `<button type="button" @click="emit" >emit data</button>`
});
app.mount('#app');
如果有傳遞參數的需求,則需要在內層的$emit
內再加上需要傳遞的參數。在外層的method
內需要定義接收的參數名稱。
$emit
不一定要撰寫在methods
內內層元件也可以直接在 template 中撰寫$emit
。這麼一來就不用另外在定義一個內層元件的method名稱。
e.g:
template:`
<button type="button"
@click="$emit('emit-text',text)"
>
</button>
`
Emit 驗證
與props
類似,emit
同樣可以在傳出參數時先進行一個驗證(驗證定義在子元件上)
與props
相同,emit
在驗證時,就算型別與定義的不同,也可以正常執行。
只是會在開發者工具中看到Vue的warning
定義emits
- html(#app)
- vue
<div id="app">
<div class="p-5">
<h3>Emits API</h3>
{{ num }}
<button-counter @add="addNum"></button-counter>
</div>
</div>
const app = Vue.createApp({
data() {
return {
num: 0,
};
},
methods: {
addNum(num) {
this.num = this.num + num;
},
}
});
app.component('button-counter', {
data() {
return {
num: 1,
}
},
emits:['add'],
// 主要會出現在該值是由 data 定義,但難以追蹤他的變化時會出現
template: `
<button type="button" @click="num++">調整 num 的值</button>
<button type="button" @click="$emit('add',num)">add</button>
`,
});
app.mount('#app');
當定義一個$emit
事件,其傳遞值由data所定義,但是又難以追蹤其變化時 (可能會隨時更改),只要定義emits
屬性就可以消除這個Vue warn。
emits
屬性值為一個陣列 ,並且在裡面使用字串方式存入向外傳遞$emit
所定義的名稱,如 Line:19(Vue) 。
驗證傳出參數型別
- html(#app)
- vue
<div id="app">
<div class="p-5">
<h3>驗證資料內容</h3>
{{num}}
<button-counter2 @add="addNum"></button-counter2>
</div>
</div>
const app = Vue.createApp({
data() {
return {
num: 0,
};
},
methods: {
addNum(num) {
this.num = this.num + num;
},
}
});
app.component('button-counter2', {
emits: {
add:(num)=>{
// 添加警告來避免開發中沒有注意到
if(typeof num !== 'number'){
console.warn('add事件所傳出的參數型別需為 number')
}
// 定義好回傳的型別要是number才會通過驗證
// 當然這邊也可以進行除了型別以外的驗證
return typeof num === 'number'
}
},
template: `
<button type="button" @click="$emit('add', '1')">Emit 驗證是否為數值</button>
`,
})
app.mount('#app');
其中emits
改寫為物件,並且屬性名稱對應$emit
所傳出的事件名稱(以此例來說即為add
)。