Vue 学习笔记:组件通信(Props / 自定义事件)与插槽(Slot)全解析

作为 Vue 初学者,组件通信插槽是实现组件复用、解耦的核心技能。这篇笔记会把这两个知识点拆解成 "一看就懂" 的形式,既是自己的学习总结,也希望能帮到同样入门的同学~

一、组件通信:父子组件的数据传递

Vue 中组件是独立的,想要实现 "组件之间传数据",核心有两种场景:父传子(Props)子传父(自定义事件)

1. 父传子:Props 传递数据(单向数据流)

父组件通过props把数据传递给子组件,子组件只能 "读取" 不能 "直接修改"(Vue 的单向数据流规则)。

示例:父组件ComponentA向子组件ComponentB传值

vue

xml 复制代码
<!-- ComponentA.vue(父组件) -->
<template>
  <h3>ComponentA</h3>
  <!-- 第一步:在子组件标签上绑定要传递的数据 -->
  <ComponentB :title="title" :age="age" :names="names"/>
</template>

<script>
import ComponentB from "./ComponentB.vue"
export default {
  components: { ComponentB },
  data() {
    return {
      title: "父组件传递的标题",
      age: 20,
      names: ["iwen", "ime"]
    }
  }
}
</script>

vue

xml 复制代码
<!-- ComponentB.vue(子组件) -->
<template>
  <p>{{ title }}</p>
  <p>{{ age }}</p>
  <p v-for="(item,index) of names" :key="index">{{ item }}</p>
</template>

<script>
export default {
  // 第二步:子组件通过props选项声明接收的数据
  props: ["title", "age", "names"]
}
</script>

进阶:Props 的类型、默认值、必填校验 实际开发中,我们可以给props加 "类型限制、默认值、必填校验",让组件更健壮。

vue

xml 复制代码
<!-- ComponentB.vue(子组件) -->
<script>
export default {
  props: {
    // 限制title的类型可以是字符串、数字、数组、对象
    title: {
      type: [String, Number, Array, Object],
      required: true // 表示title是必填项
    },
    // 限制age的类型是数字,默认值为0
    age: {
      type: Number,
      default: 0
    },
    // 数组/对象的默认值必须用工厂函数返回
    names: {
      type: Array,
      default() {
        return ["默认名称"]
      }
    }
  }
}
</script>

2. 子传父:自定义事件($emit)传递数据

子组件通过this.$emit("事件名", 数据)触发自定义事件,父组件通过@事件名监听并接收数据。

示例:子组件Child向父组件ComponentEvent传值

vue

xml 复制代码
<!-- Child.vue(子组件) -->
<template>
  <h3>Child</h3>
  <button @click="clickEventHandle">传递数据给父组件</button>
</template>

<script>
export default {
  data() {
    return {
      msg: "子组件的私有数据~"
    }
  },
  methods: {
    clickEventHandle() {
      // 触发自定义事件,并传递数据msg
      this.$emit("someEvent", this.msg)
    }
  }
}
</script>

vue

xml 复制代码
<!-- ComponentEvent.vue(父组件) -->
<template>
  <h3>组件事件</h3>
  <!-- 监听子组件的someEvent事件,触发getHandle方法 -->
  <Child @someEvent="getHandle"/>
  <p>父组件接收的子组件数据:{{ message }}</p>
</template>

<script>
import Child from "./Child.vue"
export default {
  components: { Child },
  data() {
    return {
      message: ""
    }
  },
  methods: {
    getHandle(data) {
      // 接收子组件传递的数据,并赋值给message
      this.message = data
    }
  }
}
</script>

二、插槽(Slot):让组件更灵活的 "内容插槽"

插槽的作用是让父组件可以向子组件 "注入" 自定义内容 ,实现组件的灵活复用。Vue 的插槽分为三种:默认插槽、具名插槽、作用域插槽

1. 默认插槽:最简单的 "内容注入"

子组件用<slot></slot>预留一个 "内容坑位",父组件在子组件标签内写的内容会自动填入这个坑位。

示例:父组件App向子组件SlotsTow注入内容

vue

xml 复制代码
<!-- SlotsTow.vue(子组件) -->
<template>
  <h3>Slots续集</h3>
  <!-- 预留默认插槽的坑位 -->
  <slot></slot>
</template>

vue

xml 复制代码
<!-- App.vue(父组件) -->
<template>
  <SlotsTow>
    <!-- 父组件在这里写的内容,会被注入到子组件的slot中 -->
    <h3>我是父组件注入的内容</h3>
    <p>插槽让组件变得更灵活!</p>
  </SlotsTow>
</template>

<script>
import SlotsTow from "./components/SlotsTow.vue"
export default {
  components: { SlotsTow }
}
</script>

默认内容: 如果父组件没注入内容,子组件可以给插槽设置 "默认内容"。

vue

xml 复制代码
<!-- SlotsTow.vue(子组件) -->
<template>
  <h3>Slots续集</h3>
  <!-- 没内容时显示"默认内容" -->
  <slot>父组件没传内容,我是默认显示的文字~</slot>
</template>

2. 具名插槽:多个 "命名坑位" 的精准注入

当子组件需要多个插槽坑位 时,用name给每个插槽命名,父组件用v-slot:名称(或#名称)指定内容注入到哪个坑位。

示例:子组件SlotsAttrheadermain两个具名插槽

vue

xml 复制代码
<!-- SlotsAttr.vue(子组件) -->
<template>
  <div>
    <h3>具名插槽示例</h3>
    <!-- 命名为header的插槽 -->
    <slot name="header"></slot>
    <!-- 命名为main的插槽 -->
    <slot name="main"></slot>
  </div>
</template>

vue

xml 复制代码
<!-- App.vue(父组件) -->
<template>
  <SlotsAttr>
    <!-- 用v-slot:header指定内容注入到header插槽 -->
    <template v-slot:header>
      <h4>这是头部插槽的内容</h4>
    </template>
    <!-- 用#main指定内容注入到main插槽(#是v-slot的简写) -->
    <template #main>
      <p>这是主体插槽的内容</p>
    </template>
  </SlotsAttr>
</template>

<script>
import SlotsAttr from "./components/SlotsAttr.vue"
export default {
  components: { SlotsAttr }
}
</script>

3. 作用域插槽:子组件向父组件 "反向传值" 的插槽

子组件在插槽中绑定数据(slotProps),父组件可以 "接收并使用" 这些数据,实现 "子传父式的插槽内容定制"

示例:子组件SlotsAttr向父组件传递msgdemo数据

vue

xml 复制代码
<!-- SlotsAttr.vue(子组件) -->
<template>
  <div>
    <h3>作用域插槽示例</h3>
    <!-- 插槽中绑定数据(msg和demo) -->
    <slot name="header" :msg="slotMsg" :demo="slotDemo"></slot>
    <slot name="main" :msg="slotMsg" :demo="slotDemo"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      slotMsg: "子组件传递的消息",
      slotDemo: "子组件传递的演示数据"
    }
  }
}
</script>

vue

xml 复制代码
<!-- App.vue(父组件) -->
<template>
  <SlotsAttr>
    <!-- 接收子组件传递的slotProps,并使用其中的msg和demo -->
    <template #header="slotProps">
      <h4>头部插槽:{{ slotProps.msg }} - {{ slotProps.demo }}</h4>
    </template>
    <template #main="slotProps">
      <p>主体插槽:{{ slotProps.msg }} - {{ slotProps.demo }}</p>
    </template>
  </SlotsAttr>
</template>

<script>
import SlotsAttr from "./components/SlotsAttr.vue"
export default {
  components: { SlotsAttr }
}
</script>

渲染作用域: 插槽内容是在父组件的作用域 中定义的,所以可以直接访问父组件的数据;而插槽的slotProps是子组件传递的,父组件通过v-slot接收后才能使用。

三、总结:组件通信与插槽核心要点

知识点 核心作用 关键规则 / 技巧
Props(父传子) 父组件向子组件传递数据 子组件只能读不能直接改;支持类型、默认值、必填校验;数组 / 对象默认值需用工厂函数
自定义事件(子传父) 子组件向父组件传递数据 / 事件 子组件用this.$emit("事件名", 数据)触发;父组件用@事件名监听
默认插槽 父组件向子组件注入单个自定义内容 子组件用<slot></slot>预留坑位;父组件在子组件标签内写内容即可注入
具名插槽 父组件向子组件注入多个命名的自定义内容 子组件用name给插槽命名;父组件用v-slot:名称(或#名称)指定注入位置
作用域插槽 子组件向父组件传递数据,父组件定制插槽内容 子组件在插槽中绑定数据(slotProps);父组件用v-slot="slotProps"接收并使用

掌握这些知识点后,Vue 组件的复用性和灵活性会大幅提升~ 后续再深入学习 Vuex、Pinia 等状态管理工具,就能应对更复杂的组件通信场景了。

相关推荐
HIT_Weston15 小时前
49、【Ubuntu】【Gitlab】拉出内网 Web 服务:http.server 单/多线程分析(一)
前端·ubuntu·gitlab
涔溪15 小时前
Vue3 中ref和reactive的核心区别是什么?
前端·vue.js·typescript
天意__15 小时前
Flutter开发,scroll_to_index适配flutter_list_view
前端·flutter
吉星9527ABC15 小时前
表示离散量的echarts图型示例
前端·arcgis·echarts·离散量web展示
光影少年15 小时前
web3学习路线
前端·学习·前端框架·web3
克喵的水银蛇15 小时前
Flutter 状态管理:Provider 入门到实战(替代 setState)
前端·javascript·flutter
鹏多多15 小时前
flutter-使用url_launcher打开链接/应用/短信/邮件和评分跳转等
android·前端·flutter
刻刻帝的海角15 小时前
响应式数据可视化 Dashboard
开发语言·前端·javascript
小飞侠在吗15 小时前
vue3 中的 ref 和 reactive
前端·javascript·vue.js
0思必得015 小时前
[Web自动化] 开发者工具控制台(Console)面板
前端·javascript·python·自动化·web自动化·开发者工具