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~

感谢阅读

相关文章
相关标签/搜索