vue入门:插槽

发布于:2025-04-12 ⋅ 阅读:(34) ⋅ 点赞:(0)

插槽

  1. 插槽 API
  2. Vue 的插槽(Slot)是实现组件内容分发的一种机制,允许父组件向子组件传递自定义的内容。传什么内容,子组件就渲染什么样的内容,对组件添加属性更灵活(通过组件属性也是没有办法传递html标签的)。所以插槽是一种传递复杂内容的一种方式,通过属性是无法传递的,所以设计了插槽API.
  3. v-slot 指令自 Vue 2.6.0 起被引入,提供更好的支持 slot 和 slot-scope attribute 的 API 替代方案
  4. 如果组件中的 template 中没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。
  5. 插槽内可以包含任何模板代码。
  6. 一个不带 name 的 <slot> 出口会带有隐含的名字“default”

默认插槽(Default Slot)

是最简单的插槽形式,用于在子组件中预留一个位置,供父组件插入内容。子组件中通过 <slot></slot> 定义插槽位置

<!-- 子组件 ChildComponent.vue -->
<template>
  <div class="child">
    <slot>默认内容</slot>
  </div>
</template>

<!-- 父组件 ParentComponent.vue -->
<template>
  <ChildComponent>
    <p>这是父组件传递的内容</p>
  </ChildComponent>
</template>

具名插槽(Named Slot)

  • 当需要多个插槽时,可以通过 name 属性区分不同的插槽,
  • 子组件中通过 <slot name="插槽名称"></slot> 定义具名插槽。
  • 父组件通过 <template v-slot:插槽名称> 绑定内容
<!-- 子组件 ChildComponent.vue -->
<template>
  <div class="child">
    <slot name="header">默认头部内容</slot>
    <slot>默认主体内容</slot>
    <slot name="footer">默认底部内容</slot>
  </div>
</template>

<!-- 父组件 ParentComponent.vue -->
<template>
  <ChildComponent>
    <template v-slot:header>
      <h1>这是头部内容</h1>
    </template>
    <p>这是主体内容</p>
    <template v-slot:footer>
      <p>这是底部内容</p>
    </template>
  </ChildComponent>
</template>

作用域插槽(Scoped Slot)

  • 作用域插槽允许子组件向父组件传递数据,并让父组件决定如何渲染这些数据
  • 子组件通过 标签的 v-bind 属性传递数据。
  • 父组件通过 v-slot 接收并使用这些数据。
<!-- 子组件 ChildComponent.vue -->
<template>
  <div class="child">
    <slot :user="user" :message="message"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: { name: '张三', age: 25 },
      message: '欢迎来到 Vue 插槽世界!'
    };
  }
};
</script>

<!-- 父组件 ParentComponent.vue -->
<template>
  <ChildComponent v-slot="{ user, message }">
    <p>用户名:{{ user.name }}</p>
    <p>年龄:{{ user.age }}</p>
    <p>{{ message }}</p>
  </ChildComponent>
</template>

案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
<div id="app">

    {{message}} {{message + message}}

    <div :id="message"></div>

    <todo-list>
        <!--
        todo-list 组件中不设置 slot 标签时,  vue 是不知道标签 todo-item 挂在 标签 todo-list 下的
        在 todo-list 组件中, 添加一个 slot 标签时,就可以由开发者自定义一些渲染内容了
         -->
        <todo-item @delete="handleDelete" v-for="item in list" :title="item.title" :del="item.del">

            <!--
             插槽本质上是一个函数,在组件 todo-item 中 通过 slot 标签调用了这个函数,并给这个函数传递了一个参数,也就是 value 值
             子组件可以传递给父组件内容的插槽叫做作用域插槽
             -->
            <template v-slot:pre-icon="{value}">
                <span v-if="value>0.5" style="color: red">红色图标 {{value}} </span>
                <span v-else style="color: green">绿色图标 {{value}} </span>
            </template>


            <!--  如果指定了插槽时,则替换组件中 suf-icon 的默认的插槽的内容-->
            <template v-slot:suf-icon>
                <span>后置图标 😄</span>
            </template>

        </todo-item>
    </todo-list>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>

    Vue.component('todo-item', {
        props: {
            title: String,
            del: {
                type: Boolean,
                default: false,
            },
        },
        template:
                `
                  <li>

                    <slot name="pre-icon" :value="value"></slot>

                    <span v-if="!del">{{ title }}</span>
                    <span v-else style="text-decoration: line-through">{{ title }}</span>

                    <slot name="suf-icon">默认插槽值:0</slot>

                    <button v-show="!del" @click="handleClick">删除</button>
                  </li>
                `,
        data: function () {
            return {
                value: Math.random()
            }
        },
        methods: {
            handleClick(e) {
                console.log('点击删除按钮')
                this.$emit('delete', this.title)
            }
        },
    })


    Vue.component('todo-list', {
        template:
                `
                  <ul>
                    <slot></slot>
                  </ul>
                `,
        data: function () {
            return {}
        },
    })

    var vm = new Vue({
        el: '#app',
        data: {
            message: 'hello world',
            list: [{
                title: '课程1',
                del: false
            }, {
                title: '课程2',
                del: true
            }],
        },
        methods: {
            handleDelete(val) {
                console.log('handleDelete', val)
            }
        }
    })

</script>
</body>

</html>

网站公告

今日签到

点亮在社区的每一天
去签到