最常使用的Vue標籤 教你 v-slot 插槽的作用與使用

在Vue的官方文檔中,關於v-slot插槽的使用,介紹的不是非常清晰明確,插槽這個東西其實很好理解,當我們定義了一個Vue組件後,我們是不能在調用組件時在裏面再定義其它的dom結構的:

<submit-button>
  <div>Save</div>
</submit-button>

上述這種結構是不合法的,如果 submit-button組件裏 沒有包含一個 <slot> 標籤,則該組件起始標籤和結束標籤之間的任何內容都不會被顯示,會被拋棄。那如果我們想在組件中再嵌入其它的dom結構該怎麼辦呢,這個時候就可以用到插槽這個功能了。在react同樣具備這個功能,只不過他不向Vue那樣封的這麼徹底,給你幾個明明白白的屬性供你去使用,而是更貼近原生:

<!-- HTML -->
<Range>
    <Text>插槽</Text>
    <Text>react native</Text>
</Range>
// JSX語法
export default class Range extends Component {

  constructor(props) {
    super(props)
  }

  render() {
    return (
      <View style={styles.body}>
          {this.props.children}
      </View>
    )
  }

在react中是通過this.props.children這個屬性來拿到組件中定義的dom結構,並在組件中定義位置去渲染。看到react的這個示例後,對你瞭解Vue的插槽應該能起到一定的幫助。

簡單的說,插槽就是讓你能夠在組件標籤中再定義其它的DOM結構。

插槽內容

插槽內可以包含任何模板代碼,包括 HTML或者其它組件:

<!-- 添加HTML內容 -->
<touch-bar>
  <!-- 添加一個 Font Awesome 圖標 -->
  <span class="fa fa-user"></span>
  點擊這裏
</touch-bar>

<!-- 添加其它組件 -->
<touch-bar>
  <!-- 添加一個按鈕的組件 -->
  <touch-button name="user"></touch-button>
  點擊這裏
</touch-bar>

編譯作用域

在Vue當中,父級模板裏的所有內容都是在父級作用域中編譯的;子模板裏的所有內容都是在子作用域中編譯的。

<navigation-link url="/profile">
  Logged in as {{ user.name }}
</navigation-link>

在上面代碼中,該插槽跟模板的其它地方一樣可以訪問相同的實例屬性 (也就是相同的“作用域”)user.name,而不能訪問 <navigation-link> 的作用域。例如 url 是訪問不到的:

<navigation-link url="/profile">
  Clicking here will send you to: {{ url }}
</navigation-link>

這裏的 `url` 會是 undefined,因爲 "/profile" 是傳遞給<navigation-link>組件的而不是在 <navigation-link> 組件標籤內部定義的。
 

插槽的默認內容

有時爲一個插槽設置具體的後備 (也就是默認的) 內容是很有用的,它只會在沒有提供內容的時候被渲染。例如在一個 <submit-button> 組件中,我們可能希望這個 <button> 內絕大多數情況下都渲染文本“Submit”。爲了將“Submit”作爲後備內容,我們可以將它放在 <slot> 標籤內:

<button type="submit">
  <slot>Submit</slot>
</button>

現在當我在一個父級組件中使用 <submit-button> 並且不提供任何插槽內容時,後備內容“Submit”將會被渲染,但是如果我們提供內容,則這個提供的內容將會被渲染從而取代後備內容:

<!-- 不提供內容 -->
<submit-button></submit-button>

<!-- 提供內容 -->
<submit-button>
  Save
</submit-button>

具名插槽

有時我們在一個組件需要多個插槽,每個插槽被用在組件的不同的位置,對於這樣的情況,<slot> 元素有一個特殊的特性:name這個特性可以用來定義額外的插槽的名稱,一個不帶 name 的 <slot> 會默認帶有隱含的屬性“default”:

<!-- 組件定義 -->
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

那麼我們該如何使用呢?在向具名插槽提供內容的時候,我們可以在一個 <template> 元素上使用 v-slot 指令,並以 v-slot 的參數的形式提供其名稱:

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

注意: v-slot 只能添加在一個 <template> 上

作用域插槽

有時讓插槽內容能夠訪問子組件中才有的數據是很有用的,這就正好解決了上面所說的編譯作用域的問題。例如,設想一個帶有如下模板的 <current-user> 組件,我們想讓它的後備內容顯示用戶的名,以取代正常情況下用戶的姓,如下:

<!-- current-user組件定義 -->
<span>
  <slot>{{ user.lastName }}</slot>
</span>

<!-- 使用current-user組件 -->
<current-user>
  {{ user.firstName }}
</current-user>

上述代碼不會正常工作,因爲只有父級中 <current-user> 組件可以訪問到 user.firstName ,我們提供的內容是在父級渲染的,所以在<current-user>組件中定義的插槽拿不到user.lastName

爲了讓 user 在父級的插槽內容中可用,我們可以將 user 作爲 <slot> 元素的一個特性綁定上去,綁定在 <slot> 元素上的特性被稱爲插槽 prop

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

在父級作用域中,我們還可以給<current-user>中的 v-slot 給定一個值來定義插槽 prop 的名字:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

以上就是關於Vue插槽的講述!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章