Vue-(十三)自訂事件

使用 v-on 綁定自訂事件

codepen結果呈現

當內層組件要傳送資料到外層時,內層組件使用 this.$emit 提交自定義事件、資料,上層則用 v-on 或縮寫 @ 接應。

舉例說明:

  • 內層組件發出一個$emit,自定義事件為’emit-count’並帶有一個資料’this.count’
  • 外層則用 @emit-count 接應該事件,當該事件被出發時,則會執行 ‘emitCount’ 方法
    1
    2
    3
    4
    <div id="app">
    <my-counter @emit-count="emitCount"></my-counter>
    <h3>{{outerCount}}</h3>
    </div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Vue.component('my-counter',{
template:
`
<div>
<h1>{{count}}</h1>
<button @click="addOne">+1</button>
<button @click="emit">emit</button>
</div>
`,
data(){
return{
count:0,
}
},
methods:{
addOne(){
this.count += 1;
},
emit(){
this.$emit('emit-count',this.count);
},
},
});

new Vue({
el:"#app",
data:{
outerCount:0,
},
methods:{
emitCount(count){
this.outerCount = count;
},
}
})

給組件綁定原生事件

上層組件上層組件除了可以偵聽自定義事件,也可以去偵聽從內層組件發出來的原生事件,如果要偵聽「原生事件」,要加上.native 修飾符。

舉例說明:

  • 外層使用 `@click.native` 接偵聽內層物件的click事件是否被觸發,當該事件被出發時,則外層會執行 ‘clickBtn’ 方法

codepen結果呈現

1
2
3
4
5
<div id="app>
<my-button @click.native="clickBtn">

</my-button>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
Vue.component('my-button',{
template:`<button>Button</button>`,
});

new Vue({
el:"#app",
methods:{
clickBtn(){
alert('Clicked');
}
}
})

.sync修飾符

外層資料透過 props 將傳進給內層,內層經過獨立處理之後,若希望內層資料也能夠將資料更新到外層,依照前面的方法,可以在內層使用 $emit 將資料再往外傳。

舉例說明:

  • 先使用 props 傳 ‘outer-count’ 給內層,並賦值給內層的 ‘innerCount’
  • 當觸發 ‘clickSync’ 事件時,透過 $emit 將’this.innerCount’ 往外層傳送
  • 外層則透過 @sync-count 偵聽到自定義事件被觸發後,則執行 ‘syncCount’方法,方法中再重新賦值
1
2
3
4
5
<div id='app'>
<my-counter @sync-count="syncCount" :outer-count='outerCount'>
</my-counter>
<h3>{{outerCount}}</h3>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Vue.component('my-counter',{
template:`
<div>
<h1>{{innerCount}}</h1>
<button @click="innerCount+=1">+1</button>
<button @click="clickSync">sync</button>
</div>
`,
props:["outer-count"],
data(){
return {
innerCount:this.outerCount,
};
},
methods:{
clickSync(){
this.$emit('sync-count',this.innerCount)
},
},
})

new Vue({
el:"#app",
data:{
outerCount:10,
},
methods:{
syncCount(innerCount){
this.outerCount = innerCount;
}
}
})

不過,使用 .sync 修飾符,可以讓程式碼更簡潔

codepen結果呈現

舉例說明:

  • 內層透過 $emit 傳送 update:outCount事件到外層
  • 外層不使用 @ 去偵聽內層透過 $emit 傳送進來的自定義事件
  • 外層直接在傳入 props 的地方加上 .sync 修飾符, :outer-count.sync 去偵聽 ‘outer-count’的更動事件,其意義等同於 @update:outer-count="value => outerCount = count"
1
2
3
4
5
<div id='app'>
<my-counter :outer-count.sync='outerCount'>
</my-counter>
<h3>{{outerCount}}</h3>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Vue.component('my-counter',{
template:`
<div>
<h1>{{innerCount}}</h1>
<button @click="innerCount+=1">+1</button>
<button @click="clickSync">sync</button>
</div>
`,
props:["outer-count"],
data(){
return {
innerCount:this.outerCount,
};
},
methods:{
clickSync(){
this.$emit('update:outerCount',this.innerCount)
},
},
})

new Vue({
el:"#app",
data:{
outerCount:10,
},
})

自訂組件的 v-model

1
2
3
4
5
//常見 v-model 的用法
<my-counter v-model="outerCOunt"></my-counter>

//拆解上述 v-model 的意義,等同於下方程式碼
<my-counter :value="outerCount" @input='val => outerCount = val'></my-counter>

自定義 model 事件

1
2
3
4
5
6
7
8
9
10
Vue.component('my-counter',{
...
...
model:{
prop:"value",
event:"input",
}
...
...
})

codepen結果呈現

舉例說明:

1
2
3
4
5
6
7
8
<div id="app">
<!--v-model寫法: -->
<my-counter v-model="outerCount"></my-counter>

<!--意義等同於: -->
<my-counter :count="outerCount" @update:count="val=> outerCount=val"></my-counter>
<h3>{{outerCount}}</h3>
</app>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Vue.component('my-counter',{
model:{
prop:'count',
event:'update:count',
},
props:['count'],
data(){
return {
innerCount:this.count,
}
},
methods:{
syncCount(){
this.$emit('update:count',this.innerCount)
},
},
template:
`<div>
<h1>{{innerCount}}</h1>
<button @click="innerCount+=1">+1</button>
<button @click="syncCount">sync</button>
</div>
`,
});

new Vue({
el:"#app",
data:{
outerCount:10,
},
})

跨組件的溝通

上、下組件的溝通,可以透過 $emitprops來做溝通、傳遞資料,但如果組件之間並非上、下關聯,而是跨組件的關係,則有幾種溝通方式:

  1. 使用多次 $emitprops 傳遞:不建議,會造成混亂
  2. 使用 event bus
  3. 使用 Vuex

event bus

專門用來發出事件跟偵聽事件的渠道,本身是一個 Vue 實體,不綁定任何 element

codepen結果呈現

舉例說明:

  • 首先 const bus = new Vue(); 創建一個 Vue 實體來代表 event bus
  • 要推送資料給 event bus,使用 bus.$emit 發送 ‘add’ 事件給 event bus
  • 要從 event bus 接受事件、資料,則是在 mounted 生命週期階段裡,用 bus.$on 去偵聽 ‘add’ 事件
1
2
3
4
<div id="app">
<my-count></my-count>
<my-button></my-button>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const bus = new Vue();

Vue.component('my-count',{
template:'<h1>{{count}}</h1>',
data(){
return{
count:0,
};
},
mounted(){
bus.$on('add',()=>{
this.count += 1;
});
},
});

Vue.component('my-button',{
template:'<button @click="add">+1</button>',
methods:{
addOne(){
bus.$emit('add')
},
},
});

new Vue({
el:"#app",
});
© 2020 Leah's Blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero