【Vue.js】插槽

概念:

类似于 Web Component, Vue 提供的插槽也是作为模板标识替换的占位标签进行使用的

为什么需要有插槽?

  • 插槽的使用本身也是为了弥补 props 传递时直观性不足的
  • 对于复杂的模板数据,props,attrs 都是不易传递的

如何使用插槽?

基本使用:

在组件调用时使用插槽需要经历两个步骤:

  1. 在组件内部声明插槽
html 复制代码
<template>
  <slot></slot>
</template>

<script>
  import { defineComponent } from 'vue';

  export default defineComponent({
    name: 'MyComponent',
    props: {
      // ...
    },
  });
</script>
  1. 在调用组件的时候传入需要替换插槽的模板
html 复制代码
<template>
  <my-component>组件
    <p>Content</p>
  </my-component>
</template>

<script>
  import { defineComponent } from 'vue';
  import MyComponent from './components/MyComponent';

  export default defineComponent({
    name: 'App',
    components: {
      MyComponent
    },
  });
</script>

补充

  1. slot 可以理解成是一个 vue 的内置组件
  2. slot 的调用机制可以理解成是定义了一个回调函数,组件调用时触发这个回调函数
  3. 在不传递 name(通常我们称之为匿名插槽 )时,slot 的 name 为 default

使用单个插槽示例:

在组件调用使用插槽时,我们可以在插槽中传递:

  • 文本
  • 元素(单个或多个)
  • 组件 (单个或多个)
html 复制代码
<!-- 直接插入文本 -->
<my-component>
  balala
</my-component>
<!-- 插入其他的模板元素 -->
<MyComponent>
  <h2>content</h2>
</MyComponent>
<!-- 插入组件 -->
<my-component>
  <component-1 />
  <component-2 />
  <component-3 />
</my-component>

总结 - 定义插槽的规则:

  1. 在 slot 中可以插入文本, HTML, 组件
  2. 在定义 slot 的时候, 之间的值是默认值
  3. 组件的属性 props 是私有的, 不能够在插槽中直接访问
  4. 在匿名插槽定义多个元素时,最好使用 <template> 包裹一下

具名插槽

为啥插槽还需要写名字呢?

有时候,我们的组件有多个不确定渲染的位置,这个时候我们就需要使用具名插槽了。

基本使用:

具名插槽的使用步骤和匿名插槽是几乎一样的

  1. 在组件内部声明插槽
html 复制代码
<template>
  <div>
    <slot name="header"></slot>
    <slot name="default"></slot>
    <slot name="footer"></slot>
  </div>
</template>

<script>
  import { defineComponent } from 'vue';

  export default defineComponent({
    name: 'MyComponent2',
    props: {
      // ...
    },
  });
</script>
  1. 在调用组件的时候传入需要替换插槽的模板
html 复制代码
<template>
  <div>
    <MyComponent2>
      <template #header>
        <header>Header</header>
      </template>
      <template #default>
        <section>Content</section>
      </template>
      <template #footer>
        <footer>
          Footer
        </footer>
      </template>
    </MyComponent2>
  </div>
</template>

<script>
  import { defineComponent } from 'vue';
  import MyComponent2 from './components/MyComponent2.vue';

  export default defineComponent({
    name: 'App',
    components: {
      MyComponent2
    },
  });
</script>

具名插槽的一些注意点:

  1. 通过 name 定位匹配替换的相应的内容, 组件调用时可以替换多个不同的 slot

  2. 用法 v-slot:name (语法糖 #name)

  3. 原则上, v-slot 只能用在 template 上面

  4. 结合具名函数和匿名函数进行对比 (将一个具名函数(匿名函数)赋值给一个js变量)

    js 复制代码
    var foo = function () {};
    var foo = function foo1() {}
  5. v-slot:default可以替换一个匿名插槽

  6. 使用v-slot时, 可以同时替换多个匿名插槽

  7. 可以在组件中声明多个具名插槽位

作用域插槽

  1. 和组件一样, slot 中也可以传递 props 属性值, 用户可以在使用插槽时在 v-slot 中接收到这些值
html 复制代码
<template>
  <div class="comp">
    <slot name="default" :myId="myId" :myName="myName"></slot>
    <slot name="footer"></slot>
  </div>
</template>

<script>
  import { defineComponent } from 'vue';

  export default defineComponent({
    name: 'MyComponent3',
    props: {
      id: Number,
      name: String
    },
    data() {
      return {
        myId: -1,
        myName: 'hahaha'
      };
    },
    mounted() {
      this.myId = this.id;
      this.myName = this.name;

      setTimeout(() => {
        this.myName = 'Baby Wong';
      }, 2000);
    }
  });
</script>
html 复制代码
<template>
  <MyComponent3 :id="1" name="王宝宝">
    <template #default="{ myId, myName }">
      <p>ID: {{ myId }}</p>
      <p>Name: {{ myName }}</p>
    </template>
  </MyComponent3>
</template>

<script>
  import { defineComponent } from 'vue';
  import MyComponent3 from './components/MyComponent3.vue';

  export default defineComponent({
    name: 'App',
    components: {
      MyComponent3
    }
  });
</script>
  1. 使用作用域插槽时, 如果没有其他的插槽, 可以使用 v-slot="xxx" / #default=""

  2. 如果容器只有默认一个插槽,可以直接在容器上面v-slot获取值 (props | 解构) (这是唯一的一种情况, v-slot可以在非 template 上写)

  3. 类似ES6

    • v-slot 插槽可以支持解构 (类似ES6对象解构)
    • v-slot插槽可以有默认值(ES6 解构默认值)

动态插槽

  • 在不确定使用什么插槽时, 我们可以通过数据动态控制渲染的插槽v-slot:[slotName]
  • 动态插槽用的比较少,了解一下即可
html 复制代码
<template>
  <Comp v-slot:[slotName] />
</template>

<script>
  import { defineComponent } from 'vue';

  export default defineComponent({
    name: 'App',
    computed: {
      slotName() {
        const num = Math.random();

        if (num > .5) {
          return 'main';
        }
        return 'default';
      }
    }
  });
</script>
相关推荐
姚*鸿的博客13 分钟前
pinia在vue3中的使用
前端·javascript·vue.js
天下无贼!2 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
爱喝水的小鼠3 小时前
Vue3(一) Vite创建Vue3工程,选项式API与组合式API;setup的使用;Vue中的响应式ref,reactive
前端·javascript·vue.js
小晗同学3 小时前
Vue 实现高级穿梭框 Transfer 封装
javascript·vue.js·elementui
forwardMyLife3 小时前
element-plus的面包屑组件el-breadcrumb
javascript·vue.js·ecmascript
计算机学姐4 小时前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
luoluoal4 小时前
java项目之基于Spring Boot智能无人仓库管理源码(springboot+vue)
java·vue.js·spring boot
mez_Blog4 小时前
个人小结(2.0)
前端·javascript·vue.js·学习·typescript
深情废杨杨5 小时前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js
GHUIJS5 小时前
【vue3】vue3.3新特性真香
前端·javascript·vue.js