【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>
相关推荐
咖啡の猫1 小时前
Vue全局事件总线
前端·javascript·vue.js
白水清风2 小时前
Vue3之渲染器
前端·vue.js·面试
白水清风2 小时前
Vue3之组件化
前端·vue.js·面试
白水清风2 小时前
Vue3之响应式系统
vue.js·面试·前端工程化
console.log('npc')3 小时前
使用 Vue3 和 Element Plus 实现选择新增用户集下拉选项框,切换类型,有物业,网格,电子围栏,行政区划管理
javascript·vue.js·elementui
一只小阿乐3 小时前
做一个vue3 v-model 双向绑定的弹窗
javascript·vue.js·elementui·vue3·v-model
前端付豪3 小时前
项目启动:搭建Vue 3工程化项目
前端·javascript·vue.js
小琴爱减肥3 小时前
Vue3 组合式 API 实战
vue.js
秋田君3 小时前
3D热力图封装组件:Vue + Three.js 实现3D图表详解
javascript·vue.js·3d·three.js·热力图
一枚前端小能手4 小时前
🔄 重学Vue之生命周期 - 从源码层面解析到实战应用的完整指南
前端·javascript·vue.js