iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 28
0
自我挑戰組

每天來點 Vue.js 吧系列 第 28

Vue slot:作用域插槽、具名插槽的縮寫

tags: Vuejs

作用域插槽

<slot> 內容在父模板編譯,基於 Vue 的定義,在父模板中編譯的內容訪問 parent scope,在子模板中編譯的內容訪問 child scope,我們不能使用插槽內容訪問 child scopeproperty

例如來說,我有一個子組件內容如下:

Vue.component('my-component', {
  data() {
    return {
      user: {
        name: 'Tony',
        nickname: 'TT',
        age: 23,
        born: 1999
      },
    }
  },
  template: `<div>
  <h2>name:<slot name="name">{{ user.nickname }}</slot></h2>
  <p>age:<slot name="age">{{ user.age }}</slot></p>
</div>`,
})

假如今天父組件想將 user.nickname 更改為呈現子組件中的 user.name ,如下方程式碼:

const vm = new Vue({
  el: '#app',
  data: {},
  template: `
  <div id="app">
    <my-component>
      <template v-slot:name>{{ user.name }}</template>
      <template v-slot:age>{{ user.born }}</template>
    </my-copmonent>
  </div>`,
})

不出意外的,由於該處不能訪問 child scope,Vue 將會給你滿江紅,和你說 user 是未定義的。

這是由於 user 位於子組件中,下方 Vue devtools 顯示了 rootmy-component instance 各自的數據,在各自的模板中可以訪問各自實體的數據。

若是想要在插槽中使用 child scope 中的數據,Vue 提供了一種方式,作用域插槽,透過該方式便可以使插槽使用子組件數據。

使用作用域插槽

如果想要使用插槽訪問 child scope 的內容,可以使用 slot Prop ,將想要給插槽訪問的 child scope 數據透過 v-bind 綁定在 <slot> 中,此時父組件的 插槽 便可以訪問該數據:

要使用作用域插槽,透過以下步驟:

  1. 在子組件插槽使用 v-bind 綁定插槽 prop
  2. 父組件使用 v-slot:插槽名稱="插槽 prop 名稱" 定義插槽 prop 名稱。(沒有給予插槽名稱時為 default,但使用多個插槽建議一律使用有參數的 v-slot
Vue.component('my-component', {
  data() {
    return {
      user: {
        name: 'Tony',
        nickname: 'TT',
        age: 23,
        born: 1999
      },
    }
  },
  template: `<div>
  <h2>name:<slot name="name" v-bind:user="user">{{ user.nickname }}</slot></h2>
  <p>age:<slot name="age" v-bind:user="user">{{ user.age }}</slot></p>
</div>`,
})
const vm = new Vue({
  el: '#app',
  template: `
  <div id="app">
    <my-component>
      <template v-slot:name="slotProp">{{ slotProp.user.name }}</template>
      <template v-slot:age="otherSlotProp">{{ otherSlotProp.user.born }}</template>
    </my-component>
  </div>`,
})

上方的插槽 prop 由於本身在 Vue 中的作用原理如下:

function (slotProp) { ... }

所以我們可以使用解構的方式簡化程式碼:

<my-component>
  <template v-slot:name="{ user }">{{ user.name }}</template>
  <template v-slot:age="{ user }">{{ user.born }}</template>
</my-component>

運用解構語法更可以支持我們重命名:

<my-component>
  <template v-slot:name="{ user: person }">{{ person.name }}</template>
  <template v-slot:age="{ user: person }">{{ person.born }}</template>
</my-component>

或是定義默認內容,適用於沒有 slotProp 的情況:

<my-component>
  <template v-slot:name="{ user: { name: 'Ady'} }">{{ user.name }}</template>
  <template v-slot:age="{ user: { born: 1992 } }">{{ user.born }}</template>
</my-component>

動態 slot 名稱

v-slot 也支持動態參數名稱:

<my-component>
  <template v-slot:[name]="{ user: { name: 'Ady'} }">{{ user.name }}</template>
  <template v-slot:[age]="{ user: { born: 1992 } }">{{ user.born }}</template>
</my-component>

具名插槽的縮寫

插槽也有縮寫語法,只適用於 具名 插槽,寫法很簡單,只需要將 v-slot 取代成 #

<my-component>
  <template v-slot:name="{ user: { name: 'Ady'} }">{{ user.name }}</template>
  <template v-slot:age="{ user: { born: 1992 } }">{{ user.born }}</template>
</my-component>

可以簡化為:

<my-component>
  <template #name="{ user: { name: 'Ady'} }">{{ user.name }}</template>
  <template #age="{ user: { born: 1992 } }">{{ user.born }}</template>
</my-component>

以上為此次內容,感謝看到這裡的你,我們明天見。


若是文中有任何錯誤、錯字、想討論的內容,歡迎各位大大不吝鞭笞指正、交流分享,筆者不慎感激 ✦ ✦ ✦

▶︎ 筆者 github:https://github.com/YUN-RU-TSENG
▶︎ 老王賣瓜之筆者另一篇鐵人:每天來點 CSS Specification

▶︎ 倘若不斷向深處扎根,似乎就能茁壯成長 - RM


參考資料:

  1. Vuejs.org 2.x

上一篇
Vue slot: 具名插槽
下一篇
Vue 動態組件
系列文
每天來點 Vue.js 吧30

1 則留言

0
Chris
iT邦新手 5 級 ‧ 2020-10-14 07:31:32

內外翻過來的 component

我要留言

立即登入留言