Vue躬行記(6)——內容分發
Vue提供了一種內容分發技術,可將父元件中的內容傳遞給子元件的模板,實現方式參照了Web元件規範草案。
一、插槽
Vue內建了一個<slot>元素,能作為插槽(slot)存在,而插槽內可包含文字、HTML片段、元件等。以下面的btn元件為例,其模板中包含一個<slot>元素,在DOM中為btn元件添加了文字內容。
<btn>提交</btn> <script> Vue.component("btn", { template: '<button><slot></slot></button>' }); </script>
渲染出的<button>元素會包含“提交”,即插槽被替換成了分發的內容,如下所示。
<button>提交</button>
在插槽中允許新增預設的內容(即為<slot>元素附加內容,如下所示),當父元件沒有傳遞內容時,它們就會被渲染。
Vue.component("btn", { template: '<button><slot>提交</slot></button>' });
二、具名插槽
具名插槽是指包含名稱的插槽,即指定了name特性的<slot>元素。當元件的模板中需要多個插槽時,就得通過名稱來加以區分。例如有一個page元件,包含三個<slot>元素,其中有兩個聲明瞭name特性,如下所示。
Vue.component("page", { template: `<div> <header><slot name="header"></slot></header> <section><slot></slot></section> <footer><slot name="footer"></slot></footer> </div>` });
如果要向具名插槽傳遞內容,那麼可以在<template>元素上使用v-slot指令,並讓插槽名稱成為它的引數,如下所示。
<page> <template v-slot:header> <h1>頭部</h1> </template> <p>內容</p> <template v-slot:footer> <h1>尾部</h1> </template> </page>
渲染出的DOM結構如下所示,分發的內容替換了對應的插槽。
<div> <header> <h1>頭部</h1> </header> <section> <p>內容</p> </section> <footer> <h1>尾部</h1> </footer> </div>
所有沒有被包裹在帶v-slot指令的<template>元素中的內容(例如上面的<p>元素),都會傳遞給沒有名稱的插槽(即預設插槽)。
注意,一個不帶name特性的<slot>元素,其實也有名稱,叫default。在v-slot指令中,也可以對其進行指定,如下所示。
<template v-slot:default> <p>內容</p> </template>
v-slot指令不僅支援動態引數,還允許特殊的縮寫,即將引數前的v-slot:替換成#號,如下所示。
<template v-slot:[obj.header]></template> <template #header></template>
三、作用域插槽
在講解作用域插槽之前,需要要先了解一下編譯作用域。
1)編譯作用域
父元件模板中的內容都是在父級作用域中編譯的,而子元件模板中的內容都是在子級作用域中編譯的,即兩級作用域中的資料無法相互訪問。下面以btn元件為例,它的模板中包含一個插槽,並在資料物件中聲明瞭一個txt屬性。
Vue.component("btn", { data: function() { return { txt:"提交" }; }, template: '<button><slot></slot></button>' });
在為btn元件提供插值形式的內容時,如下程式碼所示,由於當前作用域不存在txt屬性,因此會丟擲錯誤。
<btn>{{txt}}</btn>
2)作用域插槽
這是一種特殊的插槽,其內容可訪問子元件中的資料,即把模板傳給插槽而不是渲染好的內容。還是以btn元件為例,與之前不同的是,為<slot>元素自定義了一個txt特性,併為其繫結資料物件的txt屬性,如下所示。
Vue.component("btn", { data: function() { return { txt:"提交" }; }, template: '<button><slot :txt="txt"></slot></button>' });
在使用btn元件時,需要為v-slot指令傳遞一個變數,名稱可自定義(例如slots),其值是由插槽上的自定義特性所組成的物件。
<btn> <template v-slot:default="slots"> {{slots.txt}} </template> </btn>
當只提供了預設插槽時,可將v-slot指令轉移到元件上,並且可省略default名稱,如下所示。
<btn v-slot="slots"> {{slots.txt}} </btn>
注意,縮寫形式的預設插槽不能與具名插槽混用,因為這樣會導致作用域不明確。
<btn v-slot="slots"> {{slots.txt}} <template v-slot:custom></template> </btn>
&n