最近在 youtube 找到一個學習 webpack 很好用的教學影片,所以正努力的學習 webpack 中,一個不小心就太沉迷在新技術的練習了,導致有點忽略 Vue.js 的筆記,再次跟自己喊話,一定要做完 Vue.js 的系列(之後還有 Vuex 跟 Vuetify 呢!)。
另外說明一下,我筆記的順序是我自己認為這樣的順序比較好理解,所以會跟文件中的說明順序有差異。
新增插槽並設定插槽內容
在設定模組時,會透過 template
來決定模組在頁面上要顯示的內容,而我們可以在 template
中加入 <slot>
標籤來設定模組標籤內容的位置,並且在網頁顯示的時候,模組標籤的內容會取代該 <slot>
標籤。
模組標籤裡的內容可以是純文本、 HTML 標籤或其他模組等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <basic-slot> Next <i class="fas fa-angle-right"></i> </basic-slot> <script> Vue.component("basic-slot", { // <slot></slot>指定外層模組標籤內容放置的位置 // 可放入純文本、html標籤、其他模組 template: `<div> <div> <slot></slot> </div> </div>` }); </script>
|
插槽預設值
直接在 <slot>
標籤內寫定預設內容,如果模組標籤內沒有任何內容,那麼該 component 的畫面顯示就是該預設內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <basic-slot></basic-slot> <script> Vue.component("basic-slot", { // 在 <slot> 標籤中設定模組畫面內容的預設值 template: `<div> <div> <slot> Preview </slot> </div> </div>` }); </script>
|
具名插槽
如果要將不同內容的插槽資料分類,就可以透過 <slot name="slotName">
及 v-slot:slotName
的來命名插槽及決定不同內容所放置的位置。
如果 <slot
標籤未命名的話,預設的名字是 default
,所以在模組標籤可以透過 v-slot:default
或是不寫 v-slot:default
來找到那個未命名的 <slot
標籤。
須注意 v-slot
只能添加在 <template>
上。除非是只有默認插槽的狀況才可寫在模組標籤上
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 36 37 38
| <name-slot> <template v-slot:footer> <h4>Here is footer</h4> </template> <template v-slot:header> <h4>Here is header</h4> </template> <template v-slot:container> <h4>Here is container</h4> </template> <template> <h4>Here is default</h4> </template>
<template v-slot:default> <h4>Here is default</h4> </template> </name-slot> <script> Vue.component("name-slot", { // 在 <slot> 標籤中利用 attribute 來命名插槽,並決定不同名字的插槽內容在畫面顯示後的位置 template: `<div> <div> <slot name="header"></slot> <slot name="container"></slot> <slot name="footer"></slot> <slot></slot> </div> </div>` }); </script>
|
只有下面這種情況才可以將 v-slot:default
寫在模組標籤上,另外要注意也不能將 default 改成其他名字喔!
1 2 3 4 5 6 7 8 9 10
| <name-slot v-slot:default> <h4>Here is default</h4> </name-slot> <script> Vue.component("default-slot", { template: `<div> <slot></slot> </div>` }); </script>
|
模組標籤(外層)及插槽標籤(內層)內容的作用域
在模組標籤中的內容只能取得該層的資料,而在模組內的 <slot>
標籤也只能取得模組內的資料,簡單來說就是在哪設定要取資料就是只能取得那一層的資料。
模組標籤內容的作用域(外層)
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
| <scoped-slot name="Michelle"> 外層的 data 資料:{{ user.name }}, 模組內的 props 資料: {{ name }} 模組內的 data 資料: {{ user2.name }} </scoped-slot> <script> Vue.component("scoped-slot", { template: `<div> <div> <slot></slot> </div> </div>`, data() { return { user2: { name: "Linda", age: 9 } }; } }); const vm = new Vue({ el: "#vm", data: { user: { name: "Celeste", age: 18 } } }); </script>
|
以上面為例,會發現只要是想取得模組內的 data
或是 props
都會是失敗的(會出錯),但是取得外層(模組標籤那一層)資料是成功的。
插槽標籤的作用域(內層)
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
| <scoped-slot name="Michelle"></scoped-slot> <script> Vue.component("scoped-slot", { props:[ 'name' ], template: `<div> <div> <slot> 模組內的 props 資料: {{ name }}, 模組內的 data 資料: {{ user2.name }}, 外層的 data 資料:{{ user.name }} </slot> </div> </div>`, data() { return { user2: { name: "Linda", age: 9 } }; } }); const vm = new Vue({ el: "#vm", data: { user: { name: "Celeste", age: 18 } } }); </script>
|
如果是在 <slot>
中設定預設值,會發現在 <slot>
內只能取得該模組內的資料(如 data
或是 props
),如果想要取得外層的 data
資料會出錯。
模組標籤內容(外層)使用插槽標籤動態綁定值(內層)
如上面所說,一般情況下外層無法取得內層的資料,但是可以透過在 <slot name="slotName" v-bind:slotPropName="slotPropValue">
標籤上設定 Attribute 來動態綁定值以將內層的值往外傳到外層去,而外層透過 v-slot:slotName="customName"
或是 ES6語法 v-slot:slotName="{ slotPropName }"
來決定適用哪一個作用域。
使用 v-slot:slotName="customName"
設定 customName
來接收從 <slot>
接收的動態綁定值,像是將所有動態綁定的值放入 customName
這個物件中。
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
| <v-bind-slot v-slot:default="customName"> 姓{{ slotProps.user.firstName }}, 年齡{{ slotProps.user.age }} 喜歡水果{{ slotProps.fruit[0] }} </v-bind-slot> <script> Vue.component("v-bind-slot", { template: `<div> <div> <slot :user="user" :fruit="fruit"> {{ user.lastName }} </slot> </div> </div>`, data() { return { user: { lastName: "Linda", firstName: "KUO", age: 9 }, fruit: ["apple", "banana", "orange"] }; } }); </script>
|
使用 v-slot:slotName="{ slotPropName }"
透過 ES6 解構語法來將動態綁定值一一傳入。
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
| <v-bind-slot v-slot:default="{ user, fruit }"> 姓{{ slotProps.user.firstName }}, 年齡{{ slotProps.user.age }} 喜歡水果{{ slotProps.fruit[0] }} </v-bind-slot> <script> Vue.component("v-bind-slot", { template: `<div> <div> <slot :user="user" :fruit="fruit"> {{ user.lastName }} </slot> </div> </div>`, data() { return { user: { lastName: "Linda", firstName: "KUO", age: 9 }, fruit: ["apple", "banana", "orange"] }; } }); </script>
|
作用域
只有在自己那個具名插槽中有綁定的 Attribute 才可以在外層相同名字的 v-slot
作用域中使用。
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
| <v-bind-slot> <template v-slot:default="{ user, fruit }"> 姓{{ user.firstName }}, 年齡{{ user.age }} 喜歡水果{{ fruit[1] }} <br/> </template> <template v-slot:cellphone="{ cellphone, fruit }"> 姓{{ user.firstName }}, 手機{{ cellphone[2] }} 喜歡水果{{ fruit[1] }} </template> </v-bind-slot> <script> Vue.component("v-bind-slot", { template: `<div> <div> <slot name="default" :user="user" :fruit="fruit"></slot> <slot name="cellphone" :cellphone="cellphone" :fruit="fruit"></slot> </div> </div>`, data() { return { user: { lastName: "Linda", firstName: "KUO", age: 9 }, fruit: ["apple", "banana", "orange"], cellphone: ["iphone", "samsung", "oppo"] }; } }); </script>
|
動態插槽名
可以透過 v-slot:[動態插槽名]
來動態可以模組標籤內容的位置。
另須注意動態插槽名需全為小寫,因為 Vue 會自動將該動態插槽名轉為小寫,而導致在外層找不到該筆資料( dynamicslotname
!==dynamicSlotName
)。
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
| <dynamic-slot> <template v-slot:[dynamicSlotName]> I am {{dynamicSlotName}} </template> <template v-slot:[lowercaseslotname]> I am {{lowercaseslotname}} </template> </dynamic-slot> <script> Vue.component("dynamic-slot", { template: `<div> <slot name="header">Here is header</slot> <br/> <slot name="container">Here is container</slot> <br/> <slot name="footer">Here is footer</slot> <slot></slot> </div>` }); const vm = new Vue({ el: "#vm", data: { user: { name: "Celeste" }, dynamicSlotName: "header", lowercaseslotname: "footer" } }); </script>
|
v-slot
縮寫
可以將以 #
來縮寫 v-slot
,像是 v-slot:header
可以縮寫成 #header
,v-slot:footer={ user }
可以縮寫成 #footer={ user }
,另外要注意使用縮寫字符時一定要有參數,例如 #footer={ user }
, footer
即為參數,不可以只有 #={ user }
,這樣會出錯,如果是預設值的狀況可以寫成 #default={ user }
。
Demo
See the Pen
DAY14 | 跟 Vue.js 認識的30天 - Vue 模組插槽(`slot`) by Celeste6666 (@celeste6666)
on CodePen.
參考資料:
Vue.js - 插槽