slot插槽——Vue組件封裝利器

組件化是Vue中很是核心的概念,若是想要組件化,那必需要對組件進行封裝。html

而想要封裝組件,那你必定要了解slot才能更好進行封裝。vue

1.什麼是插槽?

什麼是插槽?請讓我用一張圖解釋一下數組

概述一下,就是在對已經封裝完的組件中插入本身想要定義的不一樣組件。markdown

說白了,就是封裝的組件中插入子組件,而子組件能夠根據本身需求去定義。ide

而slot插槽有三種不一樣類型的插槽,分別爲匿名插槽、具名插槽、做用域插槽。函數

2.匿名插槽

下面一段代碼,教你快速使用匿名插槽oop

<!--組件調用頁面-->
<template>
  <div class="parent">
    <child>
      <template>
        <p>插入匿名插槽</p>
      </template>
    </child>
  </div>
</template>

<script>
import Child from '@/components/Child'
export default {
  components: {
    Child
  }
}
</script>

複製代碼
<!--封裝的組件-->
<template>
  <div class="child">
    <h3>子組件:匿名插槽</h3>
    <slot></slot>
  </div>
</template>

<style scoped>
  .child {
    background: #fbd4fc;
  }
</style>
複製代碼

從代碼上看組件化

其實就是在封裝組件中,加 slot 標籤post

在要使用的標籤上,使用 template 標籤,再插入本身想要的組件。ui

固然,匿名插槽也能夠叫默認插槽,這都是別名,不一樣的叫法。

3.具名插槽

先來看看具名插槽是怎麼使用

<!--組件調用頁面-->
<template>
  <div class="parent">
    <child>
      <template v-slot:child>
        <p>插入具名插槽</p>
      </template>
    </child>
  </div>
</template>

<script>
import Child from '@/components/Child'
export default {
  components: {
    Child
  }
}
</script>
複製代碼
<!--封裝的組件-->
<template>
  <div class="child">
    <h3>子組件:具名插槽</h3>
    <slot name="child"></slot>
  </div>
</template>

<style scoped>
  .child {
    background: #b2fffc;
  }
</style>

複製代碼

經過代碼能夠很容看出

其實就是slot組件上多一個name屬性

以及template模板上多了一個v-slot

這樣就能夠快速「對號入座」

⚠️不過要注意:本文代碼基於 vue2.6.0+ 版本

看到這裏,或許有小夥伴,有個困惑,具名插槽和默認插槽什麼異同呢?

官方文檔給出的解釋: 下面我提供兩個示例,你們一看就能懂

<!--組件調用頁面-->
<template>
  <div class="parent">
    <child>
      <template>
        <p>若是不使用v-slot:就默認插入匿名插槽</p>
      </template>
    </child>
  </div>
</template>

<script>
import Child from '@/components/Child'
export default {
  components: {
    Child
  }
}
</script>
複製代碼
<!--封裝的組件-->
<template>
  <div class="child">
    <header>
      <h3>頭部div</h3>
      <slot name="header"></slot>
    </header>
    <div class="content">
      <h3>中間div</h3>
      <!-- 等價於<slot></slot> -->
      <slot name="default"></slot>
    </div>
    <footer>
      <h3>尾部div</h3>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<style scoped>
  header {
    background: #a0c0ff;
  }
  .content {
    background: #f8f59a;
  }
  footer {
    background: #ffdfdf;
  }
</style>

複製代碼

固然了,v-slot指令能夠用#代替

<!--組件調用頁面-->
<template>
  <div class="parent">
    <child>
      <template #header>
        <p>插入header</p>
      </template>
      <template>
        <p>插入中間div</p>
      </template>
      <template #footer>
        <p>插入footer</p>
      </template>
    </child>
  </div>
</template>

<script>
import Child from '@/components/Child'
export default {
  components: {
    Child
  }
}
</script>
複製代碼
<!--封裝的組件-->
<template>
  <div class="child">
    <header>
      <h3>頭部div</h3>
      <slot name="header"></slot>
    </header>
    <div class="content">
      <h3>中間div</h3>
      <!-- 等價於<slot></slot> -->
      <slot name="default"></slot>
    </div>
    <footer>
      <h3>尾部div</h3>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<style scoped>
  header {
    background: #a0c0ff;
  }
  .content {
    background: #f8f59a;
  }
  footer {
    background: #ffdfdf;
  }
</style>
複製代碼

4.做用域插槽

知道了匿名插槽和具名插槽是遠遠不夠!

由於這兩種插槽僅僅只能能把Dom插入到封裝好的組件中,

而不能獲取組件中的數據,這樣有時候是知足不了咱們的需求的。

若是想獲取組件的數據,那麼仍是得靠做用域插槽!

先來一個例子說明下

<!--組件調用頁面-->
<template>
  <div class="parent">
    <child>
      <template slot-scope="childData">
        <div v-for="(item, index) in childData.data" :key="index">
          <input type="text" :value="item"/>
        </div>
      </template>
    </child>
  </div>
</template>

<script>
import Child from '@/components/Child'
export default {
  components: {
    Child
  }
}
</script>
複製代碼
<!--封裝的組件-->
<template>
  <div class="child">
    <h3>child組件標題</h3>
    <slot :data="list"></slot>
  </div>
</template>

<script>
export default {
  data () {
    return {
      list: ['1''2''3''4''5''6''7''8''9']
    }
  }
}
</script>
<style scoped>
</style>
複製代碼

看完這段代碼,或許有些小夥伴就暈了。

別急,讓我稍加說明!

其實簡單的理解就是:封裝的組件給要插入的組件傳值

也能夠說是變相的父給子組件傳值

而template標籤中自定義了 childData

childData 下的 data 也就是 組件內部的 list 數據

由於裏面有段代碼是 :data = "list"

這樣一想簡單易懂~

還有細心的小夥伴獲取會注意到,我用了一個v-model!

試試例子,就會發現修改Input內容裏面數據也會改變

那由於是input標籤,vue中有封裝本身的v-model

他能夠雙向綁定,那若是不是input標籤,就可能須要自定義組件啦~

固然會有個辦法提供給你們

<!--組件調用頁面-->
<template>
  <div class="parent">
    <child>
      <template slot-scope="childData">
        <div v-for="(item, index) in childData.data.list" :key="index">
          <input
            type="text"
            :value="item"
            @input="changeValue(childData.data.change, index, $event)"
          />
        </div>
      </template>
    </child>
  </div>
</template>

<script>
import Child from '@/components/Child'
export default {
  components: {
    Child
  },
  methods: {
    /**
     * 改變 input 的 value 方法
     * @param change 子組件傳入的函數方法(回調函數)
     * @param index  索引值
     * @param event  獲取事件元素
     */
    changeValue (change, index, event) {
      console.log(111)
      const value = event.currentTarget.value
      change(index, value)
    }
  }
}
</script>
複製代碼
<template>
  <div class="child">
    <h3>child組件標題</h3>
    <slot :data="{list, change: onChange}"></slot>
  </div>
</template>

<script>
export default {
  data () {
    return {
      list: ['1''2''3''4''5''6''7''8''9']
    }
  },
  methods: {
    /**
     * 改變子組件 list 函數方法
     * @param index 數組索引值
     * @param value 新的 value 值
     */
    onChange (index, value) {
      this.list[index] = value
    }
  }
}
</script>
<style scoped>
</style>
複製代碼

簡單的來講,就是在組件內部提供一個函數方法去讓外部調用修改

若是你對這段話不太瞭解,那不妨看看另外一篇簡短而又幹貨滿滿的如何「修改」Vue中的prop~

感謝閱讀

相關文章
相關標籤/搜索