Vue的slot-scope的場景的我的理解

Vue的slot-scope的場景的我的理解

這篇文章不是單純把文檔的話和api拿來翻譯和演示,而是談談我對於slot-scope的使用場景的我的理解,若是理解錯誤,歡迎討論!vue

Vue的插槽slot,分爲3種ajax

  • 匿名插槽
  • 具名插槽
  • 做用域插槽

前兩種很好理解,不管就是子組件裏定義一個slot佔位符,父組件調用時,在slot對應的位置填充模板就行了。vuex

做用域插槽的慨念,文檔卻只有一句簡單的描述element-ui

有的時候你但願提供的組件帶有一個可從子組件獲取數據的可複用的插槽。api

網絡上大多數文章,也是千篇一概的翻譯這句話,但是僅憑這一句話,我想象不到slot-scope的使用場景。數組

前言

介紹了寫這篇文章的來由,接下來簡述一下本文的脈絡網絡

  • 首先,我會結合文檔上todo-list的例子,來簡單說明一下slot-scope的使用方式
  • 其次,會使用但不理解何時用,就沒有什麼意義,因此本文第二部分,談一下我的對於其使用場景的理解
  • 最後,是我翻閱網絡上關於slot-scope時,看到的一些我以爲不太恰當的案例

官方文檔slot-scope的示例

下面是2個父子的vue組件,先解釋一下2個組件作了什麼事情ui

  • 父組件僅僅是調用了子組件
  • 子組件內部實現了一個todolist列表

我建議從數據流動的角度,理解插槽做用域的使用方式,(先學會怎麼用,暫時不用理解爲何要這麼用,使用場景是第二部分)spa

  • 1.父組件傳遞了todos數組給子組件
  • 2.子組件經過props接受了數組數據,這裏應該沒有任何問題
  • 3.子組件拿到數組後v-for渲染列表,而且經過 <slot :todo="todo">的方式,把數組內的每個todo對象,傳遞給父組件
  • 4.父組件經過slot-scope="slotProps"的方式,接受todo對象,以後就能夠經過slotProps.todo.xxx的方式來使用了

因此數據的流動經歷了翻譯

  • 父組件傳遞todos數組給子組件
  • 子組件遍歷todos數組,把裏面的todo對象傳遞給父組件

好啦,這就是slot-scope的使用方法,就這麼簡單,完結撒花~

我貼出所有代碼,方便你們本身研究

父組件的源碼,也就是調用者

<template>
  <todo-list :todos="todos">
    <template slot-scope="slotProps">
      <span v-if="slotProps.todo.isComplete">✓</span>
      <span>{{slotProps.todo.text}}</span>
    </template>
  </todo-list>
</template>

<script>
import todoList from './todoList'
export default {
  data () {
    return {
      todos: [
        {
          id: 0,
          text: 'ziwei0',
          isComplete: false
        },
        {
          text: 'ziwei1',
          id: 1,
          isComplete: true
        },
        {
          text: 'ziwei2',
          id: 2,
          isComplete: false
        },
        {
          text: 'ziwei3',
          id: 3,
          isComplete: false
        }
      ]
    }
  },

  components: {
    todoList
  },

}
</script>

子組件源碼,也就是封裝組件的人

<template>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <slot :todo="todo">
      </slot>
    </li>
  </ul>
</template>

<script>
export default {
  props: {
    todos: {
      type: Array
    }
  }
}
</script>

slot-scope的使用場景的我的理解

想象一個場景:

當你要給同事封裝一個列表組件,你就須要使用做用域插槽(注意是列表或者相似列表的組件)

你開發的這個列表組件要如何使用呢?

通常來講做爲列表組件的調用者,你的同事先作ajax請求,拿到一個這樣的數組

todos: [
        {
          id: 0,
          text: 'ziwei0',
          isComplete: false
        },
        {
          text: 'ziwei1',
          id: 1,
          isComplete: true
        },
        {
          text: 'ziwei2',
          id: 2,
          isComplete: false
        },
        {
          text: 'ziwei3',
          id: 3,
          isComplete: false
        }
      ]

以後會把todso傳遞給列表組件吧,那麼列表組件內部作什麼事情呢?

列表內部確定會v-for去幫你的同事渲染這個數組嘛。 就相似element-ui裏的table組件同樣

問題的關鍵就在這裏

列表組件的循環,是發生在組件內部的,因此經過 v-for="todo in todos" ,列表組件很容易拿到每一項todo,但列表拿到數據沒用呀,列表只是一個瓜皮,它又不懂業務邏輯

這個數據是你同事的業務數據,因此這個數據必須得交給組件的調用者,也就是把數據交給你的同事纔對。

那麼你怎樣才能把每一項的todo數據給傳遞出去呢?

你會發現沒有辦法!

不管是用$emit、vuex仍是localStorage,能夠考慮一下,會發現沒有合適的時機,能讓你把todo傳遞出去

因此爲了應對這個場景下,發明了做用域插槽,列表組件能夠經過<slot :todo="todo"></slot>傳遞todo出去

你的同事能夠經過 slot-scope="slotsProps"拿到todo。

回答幾個疑問,其實若是你看懂上面的問題,應該能夠回答下面的問題。這也是我曾經的疑問

疑問1:通常不是咱們傳參數來調用組件嗎?爲何組件還把數據傳遞回來?
的確,調用ui組件時通常是咱們傳遞配置參數給他們。

可是就像elemnt-ui的table組件,你把數組傳遞給table後,是否是有時候須要拿到某一行的row對象

並根據row對象裏的字段,來判斷一些內容的顯示隱藏?

由於循環的過程發生在table組件內部,因此table組件能夠方便的獲取到每一項數據,可是這些數據最終不是給組件的,而是咱們本身要用的業務數據。因此也須要一個方式,讓調用者能拿到本身想要的數據
疑問2: 既然子組件最終還要把我給他的數據,再返還給我,那我當初還幹嗎給它,能不能就本身在父組件裏玩?
若是你不把數據給子組件固然能夠。可是就等於拋棄掉了子組件的封裝,只能你直接在父組件本身寫一個列表

畢竟你不把數據給子組件,子組件還渲染個錘子?沒有父子關係的話,也就不用什麼插槽了。

可是咱不是爲了封裝後,能夠複用嘛,總不能永遠不用組件嘛
疑問3: 父組件須要子組件的數據?那不會有$emit和vuex嘛,爲何要有slot-scope?
$emit和vuex是數據傳遞的一種方法,可是你能夠嘗試用$emit和vuex把todo傳遞給父組件。

你會發現的確沒有合適的鉤子、時機來$emit數據

一些網上我的認爲不太恰當的例子

我認爲幾種說法是不太恰當的,也是給我形成一些困惑的

  • slot-scope是什麼?就是把子組件的數據傳遞給父組件的一種方式

這種說法,會讓我以爲slot-scope跟emit和vuex是一類東西

  • 在一些例子中,把數據定義在寫死在列表組件中,展現如何把數據傳遞出去

這些舉例子的不恰當之處,我以爲是不該該把數據定義在子組件裏。

由於真正的使用場景下,子組件的數據都是來自父組件的。做爲組件內部應該保持純淨。

就像element-ui裏的table組件,確定不會定義一些數據在組件內部,而後傳遞給你。

table組件的數據都是來自調用者的,而後table會把每一行的row,在開發者須要時,傳遞出去。

這些例子雖然不是錯誤,可是我以爲反而不利於理解slot-scope

相關文章
相關標籤/搜索