接續上一篇,接下來要來瞭解如何透過事件向父元件傳遞訊息,以及如何使用插槽,還有動態元件怎麼用。
子元件透過自訂事件告知父元件
再來看一次props down, events up
。我們已經可以將資料從父元件傳給子元件了,接下來子元件要透過事件把資料傳給父元件。
使用 v-on
綁定自訂事件
每個 Vue
實體實作了事件介面(Event Interface),因此可以:
- 使用 $on(eventName) 偵聽事件
- 使用 $emit(eventName) 觸發事件
v-on
綁定事件。使用範例:
HTML<div id="vm">
<!-- 事件偵聽器 v-on:roll 縮寫為 @roll -->
<!-- 事件處理函式 showResult -->
<dice-button @roll="showResult"></dice-button>
<p>Result: {{ value }}</p>
</div>
<script>
Vue.component('dice-button', {
template: '<button @click="rollChild">Roll</button>',
methods: {
rollChild: function(){
// 取 1~6 的亂數
var value = Math.floor(Math.random() * 6) + 1;
// 觸發父元件的事件(如果有的話),並附上值
this.$emit('roll', value)
}
}
})
new Vue({
el: '#vm',
data: {
value: 1
},
methods: {
showResult: function (v) {
this.value = Number(v)
}
}
})
</script>
我們建立了一個骰子按鈕元件,元件樣板是一個按鈕元素(子元件),偵聽 click
事件,當事件發生時由 rollChild
事件處理函式處理。該函式會取得 1~6 的隨機亂數,然後使用 $emit
方法來觸發父元件的事件,當然我們並不知道父元件是不是有偵聽這個事件,但是我們並不在意,子元件只負責觸發該事件,父元件要不要偵聽是它的事。我們同時將骰子的結果附在事件觸發上送出去。在父元件中,我們偵聽由子元件發送的
roll
事件,並交由事件處理函式 showResult
去處理,它將得到的值更新到資料屬性中,和該屬性綁定的 view 會因此更新它的顯示。
元件綁定原生事件
有時候你會想要在元件上綁定原生事件,你可以加上.native
修飾符號:
JavaScript<dice-button @roll="showResult" @click.native="doIt">
使用插槽(Slot)放置內容
每個元件都有它們各自的模板,當元件和元件組合時,該如何決定如何混合來自不同元件的模板,Vue.js 提供了一個<slot>
元素,可以當成原始內容的插槽。
元件作用範圍
在使用 Slot 之前,要先瞭解元件的作用範圍。元件的作用範圍是指元件在被編譯時,只能看到自己內部的資料屬性。元件不會被假設自己是父元件(包含其他子元件),或是子元件(被其他元件包含),所以元件永遠只能存取自己內部的資料屬性。
因此,看看以下範例:
HTML<div id="vm">
<box>
<!--
這裡的內容都屬於父元件的,
因為我們還沒用到 slot,
所以編譯時這裡的內容都會被丟掉
-->
A:{{ name }}
</box>
B:{{ name }}
</div>
<script>
Vue.component('box', {
template: '<div>C:{{ name }}</div>',
data: function () {
return {
name: 'BOX'
}
}
})
new Vue({
el: '#vm',
data: {
name: 'VM'
}
})
</script>
瀏覽器看到的結果:
HTML<div id="vm">
<div>C:BOX</div>
B:VM
</div>
<box></box>
會被編譯成它的樣板內容,並且使用它自己的資料屬性,所以是 <div>BOX</div>
。這裡沒看到 A:{{ name }}
的內容,它被子元件丟掉了,看看接下來使用 slot 的情況就會比較清楚。
使用 slot
將前面的範例中加上 slot 元素(插槽):JavaScript// ...略
Vue.component('box', {
template: '<div><slot></slot>{{ name }}</div>',
// ...略
現在瀏覽器看到的是:
HTML<div id="vm">
<div>A:VM BOX</div>
B:VM
</div>
<slot></slot>
是一個插槽,可以讓父元件把資料放入這裡,你可以看到顯示的結果是 A:VM
,表示它的資料是父元件的,而不是子元件的。slot 的功能就像是一個預先設置的容器,當父元件有指定資料時,就把它放進去,如果元件中只設定一個 slot ,那父元件中所有指定的資料會全部放在其中。而且 slot 可以指定預設值,如果父元件沒有指定資料,就會顯示預設內容。
使用範例:
HTML<div id="vm">
<h1>標題H1</h1>
<box>
<p>第一段</p>
<p>第二段</p>
<p>不管幾段,全都會放入 slot 中</p>
</box>
</div>
<script>
Vue.component('box', {
template: '\
<div>\
<h2>標題H2</h2>\
<slot>預設內容</slot>\
</div>'
})
new Vue({
el: '#vm'
})
</script>
註:JavaScript 的字串斷行是使用倒斜線 \
,而且其後不能有任何字元,包含空白都不行。瀏覽器看到的結果:
HTML<div id="vm">
<h1>標題H1</h1>
<div>
<h2>標題H2</h2>
<p>第一段</p>
<p>第二段</p>
<p>不管幾段,全都會放入 slot 中</p>
</div>
</div>
<slot>預設內容</slot>
被置換成父元件指定的內容了。
有名稱的 slot
slot 可以使用name
屬性加上名稱,這樣父元件就能指定要將資料放入哪個 slot 中。
HTML<div id="vm">
<box>
<p slot="section1">第一段</p>
<p slot="section2">第二段</p>
<p>其他內容</p>
<p>很多其他內容</p>
</box>
</div>
<script>
Vue.component('box', {
template: '\
<div>\
<slot name="section1"></slot>\
<slot></slot>\
<slot name="section2"></slot>\
</div>'
})
new Vue({
el: '#vm'
})
</script>
顯示結果:
HTML第一段
其他內容
很多其他內容
第二段
動態元件
Vue.js 提供一個特殊的元素叫做<component>
,它有一個 is
屬性,我們可以動態的綁定它,這樣就可以把多個元件掛在這個 <component>
元素上,達到動態切換不同元件的功能。使用範例:
HTML<div id="vm">
<button @click="goto('home')">Home</button>
<button @click="goto('news')">News</button>
<button @click="goto('about')">About</button>
<hr>
<component :is="currentView"></component>
</div>
<script>
Vue.component('home', {
template: '<div>首頁</div>'
})
Vue.component('news', {
template: '<div>最新消息</div>'
})
Vue.component('about', {
template: '<div>關於</div>'
})
new Vue({
el: '#vm',
data: {
currentView: 'home'
},
methods: {
goto: function(v) {
this.currentView = v
}
}
})
</script>
我們建立 3 個元件分別為 home
、news
及 about
,接著設定資料屬性 currentView
的值為 home
,表示預設顯示 home
。然後加入一個 goto
方法,接受元件的名稱為參數,並將 HTML 中的 3 個按鈕事件呼叫它。當按下按鈕,改變了 currentView
的值,於是 <component :is="currentView"></component>
就會載入對應名稱的元件。你可以在 JSFiddle 上試玩:
暫存動態元件的狀態
動態元件會在每次切換時被重新建立,如果你想將被切換掉的元件暫存在記憶體中不要被銷毀,可以使用keep-alive
元素。使用範例:
HTML<keep-alive>
<component :is="currentView"></component>
</keep-alive>
你可以在元件中建立一個輸入框 <div>首頁<input type="text"></div>
,執行後在其中隨便輸入一些文字,接著點選其他按鈕,試試看有加 <keep-alive>
和沒加有什麼差別。
本文網址:http://blog.tonycube.com/2017/05/vuejs-9-2-component.html
由 Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀
由 Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀
我要留言
留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。