1. 程式人生 > >Vue躬行記(6)——內容分發

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