详细分析Vue3中的卡槽知识点(附Demo)

前言

不使用卡槽,子组件的内容是固定的,无法在父组件中进行灵活的插入和替换

<!-- ChildComponent.vue -->
<template>
  <div>
    <p>This is fixed content</p>
  </div>
</template>

使用卡槽的好处:父组件可以灵活地插入内容,使得子组件变得更加通用和可重用

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot></slot>
  </div>
</template>

1. 基本知识

卡槽(Slot)是用于在父组件中定义子组件内容的一种机制

卡槽允许在使用组件时插入内容,从而使组件更加灵活和可重用

基本用法如下:

<!-- ParentComponent.vue -->
<template>
  <ChildComponent>
    <p>This is some default slot content</p>
  </ChildComponent>
</template>

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot></slot>
  </div>
</template>

具名卡槽:(在组件中定义多个插槽,并为每个插槽指定一个名称)

<!-- ParentComponent.vue -->
<template>
  <ChildComponent>
    <template v-slot:header>
      <h1>This is the header</h1>
    </template>
    <template v-slot:footer>
      <p>This is the footer</p>
    </template>
  </ChildComponent>
</template>

<!-- ChildComponent.vue -->
<template>
  <div>
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot> <!-- Default slot -->
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

作用域插槽:将数据从子组件传递给父组件使用的插槽内容

ChildComponent 向默认插槽传递了一个 message 属性
父组件 ParentComponent 使用 slotProps 访问并显示该消息

<!-- ParentComponent.vue -->
<template>
  <ChildComponent>
    <template v-slot:default="slotProps">
      <p>{{ slotProps.message }}</p>
    </template>
  </ChildComponent>
</template>

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot :message="message"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello from ChildComponent'
    };
  }
};
</script>

2. 卡槽属性

插槽属性允许将数据从子组件传递给父组件中的插槽内容,这些值在使用作用域插槽(Scoped Slots)时特别有用

允许带上的数值:字符串、数字、布尔值、对象、数组

基础字符串和数字值:

子组件:

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot :title="title" :count="count"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: 'Hello from ChildComponent',
      count: 42
    };
  }
};
</script>

父组件:

<!-- ParentComponent.vue -->
<template>
  <ChildComponent>
    <template v-slot="{ title, count }">
      <h1>{{ title }}</h1>
      <p>Count: {{ count }}</p>
    </template>
  </ChildComponent>
</template>

对象和数组:

子组件:

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot :user="user" :items="items"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: { name: 'John Doe', age: 30 },
      items: ['item1', 'item2', 'item3']
    };
  }
};
</script>

父组件:

<!-- ParentComponent.vue -->
<template>
  <ChildComponent>
    <template v-slot="{ user, items }">
      <p>User: {{ user.name }}, Age: {{ user.age }}</p>
      <ul>
        <li v-for="item in items" :key="item">{{ item }}</li>
      </ul>
    </template>
  </ChildComponent>
</template>

3. Demo1

<!-- ParentComponent.vue -->
<template>
  <Card>
    <template v-slot:header>
      <h1>Card Header</h1>
    </template>
    <template v-slot:default="slotProps">
      <p>{{ slotProps.content }}</p>
    </template>
    <template v-slot:footer>
      <p>Card Footer</p>
    </template>
  </Card>
</template>

<!-- Card.vue -->
<template>
  <div class="card">
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot :content="content"></slot> <!-- Scoped slot -->
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<script>
export default {
  data() {
    return {
      content: 'This is the card content'
    };
  }
};
</script>

<style>
.card {
  border: 1px solid #ccc;
  padding: 1rem;
}
</style>

4. Demo2

子组件:

<!-- UserCard.vue -->
<template>
  <div class="user-card">
    <slot :user="user" :posts="posts"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: { name: 'Jane Doe', age: 25, location: 'New York' },
      posts: [
        { id: 1, title: 'My first post' },
        { id: 2, title: 'Vue is awesome' }
      ]
    };
  }
};
</script>

<style>
.user-card {
  border: 1px solid #ccc;
  padding: 1rem;
  border-radius: 4px;
}
</style>

父组件:

<!-- ParentComponent.vue -->
<template>
  <UserCard>
    <template v-slot="{ user, posts }">
      <h2>{{ user.name }}</h2>
      <p>Age: {{ user.age }}</p>
      <p>Location: {{ user.location }}</p>
      <h3>Posts:</h3>
      <ul>
        <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
      </ul>
    </template>
  </UserCard>
</template>

5. 彩蛋

比较特殊,在实战中遇到

row$index 是 el-table 组件在渲染表格时自动提供的,不需要在父组件中显式定义

属性是 el-table 组件在内部处理数据时生成的,并在每一行的数据传递过程中提供给 el-table-column 组件的插槽

将其转化为Demo所示:

<template>
  <el-form
    ref="formRef"
    :model="formData"
    :rules="formRules"
    v-loading="formLoading"
    label-width="0px"
    :inline-message="true"
  >
    <el-table :data="formData" class="-mt-10px">
      <el-table-column label="序号" type="index" width="100" />
      <el-table-column label="船名" min-width="150">
        <template #default="{ row, $index }">
          <el-form-item :prop="`${$index}.shipName`" :rules="formRules.shipName" class="mb-0px!">
            <el-input v-model="row.shipName" :disabled="formType === 'detail'" placeholder="请输入船名" />
          </el-form-item>
        </template>
      </el-table-column>
      <!-- 其他列定义相同 -->
    </el-table>
  </el-form>
</template>

<script>
export default {
  data() {
    return {
      formData: [
        { shipName: '', voyage: '', billNumber: '', boxNumber: '', boxSize: '', boxType: '', productName: '', hazardousLevel: '', hazardCode: '' },
        // 其他行数据
      ],
      formRules: {
        shipName: [{ required: true, message: '请输入船名', trigger: 'blur' }],
        // 其他表单验证规则
      },
      formLoading: false,
      formType: 'edit' // 可能是 'edit' 或 'detail'
    };
  },
  methods: {
    handleDelete(index) {
      this.formData.splice(index, 1);
    }
  }
};
</script>

<style scoped>
.mb-0px! {
  margin-bottom: 0 !important;
}
</style>

相关推荐

  1. 详细分析Vue3知识Demo

    2024-06-06 23:12:09       10 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 23:12:09       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 23:12:09       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 23:12:09       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 23:12:09       18 阅读

热门阅读

  1. Vue Router (创建 挂载)

    2024-06-06 23:12:09       7 阅读
  2. 单片机排水泵高压方案

    2024-06-06 23:12:09       7 阅读
  3. 负载均衡

    2024-06-06 23:12:09       9 阅读
  4. php的default_socket_timeout会不会影响ES连接查询

    2024-06-06 23:12:09       9 阅读
  5. Linux 多台机器之间的免密登录设置

    2024-06-06 23:12:09       9 阅读
  6. Cargo字节镜像源

    2024-06-06 23:12:09       7 阅读
  7. Flappy bird小游戏

    2024-06-06 23:12:09       11 阅读
  8. Spark大数据处理 掌握Scala运算符

    2024-06-06 23:12:09       9 阅读
  9. Debian 常用命令指南:基础篇

    2024-06-06 23:12:09       9 阅读
  10. Scala学习笔记8: 包

    2024-06-06 23:12:09       9 阅读
  11. python随机显示四级词汇 修改版直接显示释义

    2024-06-06 23:12:09       8 阅读