【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>
相关推荐
嘤嘤怪呆呆狗22 分钟前
【插件】vscode Todo Tree 简介和使用方法
前端·ide·vue.js·vscode·编辑器
码小瑞1 小时前
某些iphone手机录音获取流stream延迟问题 以及 录音一次第二次不录音问题
前端·javascript·vue.js
Tirzano1 小时前
vue3 ts 简单动态表单 和表格
前端·javascript·vue.js
赵大仁2 小时前
深入理解 Vue 3 中的具名插槽
前端·javascript·vue.js·react.js·前端框架·ecmascript·html5
一雨方知深秋2 小时前
v-bind 操作 class(对象,数组),v-bind 操作 style
前端·css·vue.js·html·style·class·v-bind
LCG元10 小时前
Vue.js组件开发-使用vue-pdf显示PDF
vue.js
哥谭居民000111 小时前
将一个组件的propName属性与父组件中的variable变量进行双向绑定的vue3(组件传值)
javascript·vue.js·typescript·npm·node.js·css3
烟波人长安吖~11 小时前
【目标跟踪+人流计数+人流热图(Web界面)】基于YOLOV11+Vue+SpringBoot+Flask+MySQL
vue.js·pytorch·spring boot·深度学习·yolo·目标跟踪
PleaSure乐事12 小时前
使用Vue的props进行组件传递校验时出现 Extraneous non-props attributes的解决方案
vue.js
土豆炒马铃薯。13 小时前
【Vue】前端使用node.js对数据库直接进行CRUD操作
前端·javascript·vue.js·node.js·html5