Vue Slot小記

咱們知道在HTML中標籤能夠分爲閉合標籤空標籤,其中大多數都是閉合標籤,只有少數空標籤,好比:<input/>`<img/><base/><hr/>等。在Vue中定義的組件也能夠採用兩種方式來書寫。html

在一個組件的<template>中假如顯示一個標題<h1>Hello World!</h1>,當咱們在調用時,不論是採用<組件名/>或者<組件名></組件名>都會顯示 「hello world!「,因爲在閉合標籤中能夠包含子節點和文本,所以咱們能夠這樣來使用<組件名>我是內容</組件名>,可是運行的結果,確什麼也沒有改變。vue

若是想要在組件傳入的內容正確投射,就須要一套機制來處理,在Vue中天然就是slot(插槽)機制,在React中能夠經過this.props.children來獲取,而在Angular中能夠經過<ng-content></ng-content>來放置轉入的內容。git

React 的處理方式

在React中傳入this.props.children的值有三種可能:github

  1. 沒有子節點,結果爲 undefined
  2. 子節點,結果爲 object
  3. 多個子節點,結果爲 array

若是要對傳入的數據進行處理,React還提供了一個工具方法React.Children來處理this.props.children。總的來講React把一切處理徹底交給開發人員來,徹底透明。編程

React的這種處理方式相對來講也更加靈活,對於Vue的做用域插槽機制也能很簡單的實現。segmentfault

Angular 的處理方式

相對於React的徹底透明模式,Angular則在傳入內容時經過屬性類(class)標籤三種模式來區分和限定內容的做用域。在組件內容使用<ng-content select="xx"></ng-content>來做爲佔位,具休使用方式以下:工具

  1. 傳屬性及屬性值
<div card-body>屬性</div>
<ng-content select="[card-body]"></ng-content>

<div card-type="body">屬性值</div>
<ng-content select="[card-type=body]"></ng-content>

<div card body>多個屬性值組合</div>
<ng-content select="[card][body]"></ng-content>
  1. 傳類(class)
<div class=".card-body">類</div>
<ng-content select=".card-body"></ng-content>

<div class="card body">多個類組合</div>
<ng-content select=".card.body"></ng-content>
  1. 傳標籤
<card-body></card-body>
<ng-content select="card-body"></ng-content>
  1. 多個插槽
<ng-content select="header"></ng-content>
<div class="body">balabala...</div>
<ng-content select="footer"></ng-content>

從上面的使用方式來看Angular的插槽功能仍是很強大的。this

Vue 的處理方式

迴歸到本文的主題,在Vue 2.6.0事後引入了新語法機制將之前版本的slotscope-slot使用一個屬性來表示。具體原因可查看其RFCcode

在新的語法中v-slot只容許使用在 組件<template></template> 標籤中,而且在只能<template>套組件和子<template>htm

  1. 默認插槽

在組件中直接放一個<slot></slot>標籤就能夠接收來自組件中的內容,若是<slot>不爲空,那麼內容將做爲默認值顯示。

在調用時就可使用v-slot:default在組件上或者其子節點<template>上。

  1. 具名插槽及縮寫

具名插槽就是把分佈在頁面中不一樣位置的<slot>分配一個名字來標識,以區分其功能。在使用時只須要給<slot>添加一個name屬性便可,例如:<slot name="footer"></slot>。在使用時把默認插槽的default換成相應的名字便可,即:<template v-slot:footer></template>

在使用過程沒有必要每次都重複寫v-slot:,同v-onv-bind同樣,v-slot也有其縮寫形式,即把參數以前的全部內容 (v-slot:) 替換爲字符 #,即<template #footer></footer>

  1. 做用域插槽

做用域插槽的機制就是被調用的組件把組件內部的狀態經過屬性暴露給當前上下文。簡單點說就是它只提供數據,至於當前數據怎麼展現它不關心,相似於React的Render Props機制。

因爲Vue官方文檔寫得很清楚明白這裏直接上知識點:

  • 解構插槽Prop
<current-user v-slot="{ user }">
  {{ user.firstName }}
</current-user>
  • 解構時提供別名和提供初始值
<current-user v-slot="{ user: person }">
  {{ person.firstName }}
</current-user>

<current-user v-slot="{ user = { firstName: 'Guest' } }">
  {{ user.firstName }}
</current-user>

官方提到在只有默認插槽時可使用插槽的縮寫語法,將v-slot:default="slotProps"寫成v-slot="slotProps",可是在使用時官方也說了不能和具名插槽混用,由於它會致使做用域不明確。

下面經過一個示例來實現React中的Render Props機制。

<template>
  <div style="height:100%" @mousemove="handleMouseMove">
    <p>The current mouse position is {{ x }}, {{ y }}</p>
    <slot :position="position"/>
  </div>
</template>

<script>
  export default {
    name: 'Mouse',
    data() {
      return {
        x: 0,
        y: 0
      }
    },
    computed: {
      position: function() {
        return {
          x: this.x,
          y: this.y
        }
      }
    },
    methods: {
      handleMouseMove(event) {
        this.x = event.clientX
        this.y = event.clientY
      }
    }
  }
</script>

而後在其它組件中調用

<mouse>
  <template v-slot:default="{position}"> 
    <img src="http://iph.href.lu/64x64?text=圖片跟隨鼠標" :style="{position: 'absolute', left: position.x + 'px', top: position.y + 'px'}"/>
  </template>
</mouse>
  1. 動態插槽

動態插槽歡迎經過編程動態控制當前組件的插槽名,使用方式以下:

<template v-slot:[dynamicSlotName]>...</template>
  1. 多層插槽的嵌套
<foo v-slot="foo">
  <bar v-slot="bar">
    <baz v-slot="baz">
      {{ foo }} {{ bar }} {{ baz }}
    </baz>
  </bar>
</foo>

總結

本文只是簡單對Vue的Slot的知識點作一個簡單的筆記,更多的知識點官方文檔比較靠譜,文中並無提到在JSX語法下的插槽使用方式,若是想要了解請查看個人另一篇文章Vue中jsx不徹底應用指南關於插槽部分的內容。

相關文章
相關標籤/搜索