🔥 一篇学会vue3父子组件操作(通信、插槽、双向数据绑定)

📌前言

关于一次性总结的文章比较少 , 加上最近写代码发现了父子双向绑定defineModel(),因此便写下这一篇。

和我其他的文章一样 , 我会根据我的理解把经常使用的简单的描述出来 , 比较冷门的可能不会写, 如有问题和缺少 , 还请大佬补充。

搭建父子组件

要进行父子组件的操作 , 首先先搭建起来 , 下面是简单搭建。

目录结构

父组件/parent/index.vue

html 复制代码
<template>
  <div>父组件</div>
  <Child> </Child>
</template>

<script setup lang="ts">
// 导出子组件
import Child from "./components/Child.vue";
</script>

<style lang="scss" scoped></style>

子组件/parent/components/Child.vue

html 复制代码
<template>
  <div>
    <div>子组件</div>
  </div>
</template>

<script setup lang="ts"></script>

<style scoped></style>

这样最简单的搭建就完成了

一、🍉通信

这是最基础的操作了 , 相信大家都会了 , 就简单描写过一遍。

1、父传子

  • 和使用内置组件一样 , 只需要在子组件的标签上打:冒号
  • 左侧子组件接收名称 , 右侧父组件传入的值就行。

父组件

html 复制代码
<template>
<div>父组件</div>
<hr />
<!-- childValue子组件接收的名称 可以写成child-value -->
<Child :child-value="parentValue"></Child>
</template>

<script setup lang="ts">
// 导出子组件
import { ref } from "vue";
import Child from "./components/Child.vue";
// 定义一个父组件值
let parentValue = ref<string>("父组件值");
</script>

子组件

代码都是ts的写法 , 如果要js的需要自行转换一下

withDefaultsts特有的写法 , 使用js的话不需要写

  • ?的意思是非必传项
  • 如果没有传并且没有给默认值打印出来是undefined,页面渲染不会显示
  • html渲染的时候props.可以不写 , 不过建议还是写上
html 复制代码
<template>
  <div>
    <div>子组件</div>
    <div>没有设置默认值: {{ props.notDefaultValue }}</div>
    <div>设置了默认值: {{ props.defaultValue }}</div>
    <div>接收到的父组件值: {{ props.childValue }}</div>
    <div>接收到的父组件值(不写props.): {{ childValue }}</div>
  </div>
</template>

<script setup lang="ts">
// 接收父组件值
const props = withDefaults(
  defineProps<{
    defaultValue?: string;
    notDefaultValue?: string;
    childValue: string;
  }>(),
  {
    defaultValue: "默认值"
  }
);
</script>

效果

2、子传父(自定义事件)

  • 因为是事件所以不是使用:冒号而是@符号
  • 左侧子组件事件名称 , 右侧父组件接收函数。

父组件

使用childEmit接收子组件事件

html 复制代码
<template>
  <div>父组件</div>
  <hr />
  <!-- childEmit可以写成child-emit -->
  <Child @child-emit="childEmit"></Child>
</template>

<script setup lang="ts">
// 导出子组件
import Child from "./components/Child.vue";
// 子组件事件
const childEmit = (value: string) => {
  console.log(value);
};
</script>

子组件

  • 使用defineEmits泛型定义一个对象 , 参数1:事件名 , 其他参数:事件参数 , 有几个传几个,可以不传
  • 使用事件的方式是调用emit并传参告诉它调用的事件和事件参数。
  • 可以设置事件返回值 , 一般没有 , 写void
html 复制代码
<template>
  <div>
    <div>子组件</div>
    <!-- 参数1:事件名 , 参数2....:传输数据 -->
    <button @click="emit('childEmit', '哈哈')">发送子组件定义事件</button>
  </div>
</template>

<script setup lang="ts">
// 设置事件 参数1:事件名 , 参数2....:传输数据
const emit = defineEmits<{
  (e: "childEmit", value: string): void;
  (e: "childEmit2", value: string, value2: number): void;
  (e: "childEmit3"): void;
}>();
</script>

效果

点击按钮

3、defineExpose(暴露)

将子组件的属性和函数暴露给父组件调用 , 如果使用的灵活是非常方便的。

注意:vue3 3.2+新增

父组件

  • 拿到子组件的DOM元素
  • 直接点出暴露属性和函数

注意: 不能在setup函数下直接调用,DOM元素还未挂载

html 复制代码
<template>
  <div>父组件</div>
  子组件属性: {{ ChildRef?.msg }}
  <hr />
  <Child ref="ChildRef"></Child>
</template>

<script setup lang="ts">
// 导出子组件
import { onMounted, ref } from "vue";
import Child from "./components/Child.vue";
// 获取子组件DOM元素
let ChildRef = ref<InstanceType<typeof Child> | null>(null);

onMounted(() => {
  // 调用子组件方法
  ChildRef.value?.childFn();
});
</script>

子组件

html 复制代码
<template>
  <div>
    <div>子组件</div>
  </div>
</template>

<script setup lang="ts">
function childFn() {
  console.log("我是子组件函数");
}

const msg = "子组件msg";
defineExpose({
  msg,
  childFn
});
</script>

效果

二、🍈插槽

有时候组件会在不同的页面上产生不同的变化 , 为了组件的兼容性 , 插槽就不可或缺了

父组件

  • 写在子标签内部
  • 默认 : 直接写
  • 支持给具体名称,具体调用
  • 支持调用多次
html 复制代码
<template>
  <div>父组件</div>
  <hr />
  <Child>
    默认数据
    <template #title>title</template>
    <template #body>body</template>
  </Child>
</template>

<script setup lang="ts">
// 导出子组件
import Child from "./components/Child.vue";
</script>

子组件

html 复制代码
<template>
  <div>
    <div>子组件</div>
    <div><slot></slot></div>
    <div><slot name="title"></slot></div>
    <div><slot name="body"></slot></div>
  </div>
</template>

效果

三、🍇双向数据绑定

这也是我最近写项目时发现的

因为使用普通的父子通信 , 我感到非常的麻烦

所以我在想能不能像input一样绑定一个值呢 , 通过查询资料也是成功发现并学会了。

注意:vue3 3.4+新增

1、基础使用

父组件

可以看到我使用v-model将值传给了子组件

html 复制代码
<template>
  <div>父组件</div>
  {{ value }}
  <hr />
  <Child v-model="value"> </Child>
</template>

<script setup lang="ts">
// 导出子组件
import { ref } from "vue";
import Child from "./components/Child.vue";
// 定义值
let value = ref<string>("默认值");
</script>

子组件

可以使用默认直接接收 , 也可以对接收值进行处理。

html 复制代码
<template>
  <div>
    <div>子组件</div>
    <input v-model="value" />
  </div>
</template>

<script setup lang="ts">
//接收父组件v-model的值
// 正常接收
let value = defineModel();

// 配置接收
let value = defineModel({
  // 是否必传
  required: true,
  // 默认值
  default: "默认内容",
  // 数据类型
  type: String,
  // 校验器 val-父组件传来的值
  validator: (val: any) => {
    // 返回false否则会发出警告
    return val;
  }
})
</script>

效果

接收到之后我使用input改变value的值 , 可以看到父组件的值也被改变了

2、进阶使用

我们已经可以基本使用双向绑定了 , 但是它还有更多的功能

  • 绑定多个数据
  • 数据初始化

父组件

  • 需要绑定多个数据 v-model:[名称]直接写就行
  • 接收时第一个参数是[名称]
html 复制代码
<template>
  <div>父组件</div>
  <div>{{ title }}</div>
  <div>{{ content }}</div>
  <hr />
  <Child v-model:title="title" v-model:content="content"> </Child>
</template>

<script setup lang="ts">
// 导出子组件
import { ref } from "vue";
import Child from "./components/Child.vue";
// 定义值
let title = ref<string>("标题");
let content = ref<string>("内容");
</script>

子组件

html 复制代码
<template>
  <div>
    <div>子组件</div>
    <input v-model="title" />
    <input v-model="content" />
  </div>
</template>

<script setup lang="ts">
let title = defineModel("title");
let content = defineModel("content", {
  // 是否必传
  required: true,
  // 默认值
  default: "默认内容",
  // 数据类型
  type: String,
  // 校验器 val-父组件传来的值
  validator: (val: any) => {
    // 返回false否则会发出警告
    return val;
  }
});
</script>

效果

📚总结

组件的应用还是很重要的 , 一个好的组件能不仅能加快开发时间 , 还能增强可维护性。

相关推荐
栈老师不回家1 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
前端啊龙1 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js
一颗松鼠1 小时前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
小远yyds1 小时前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
程序媛小果2 小时前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
小光学长2 小时前
基于vue框架的的流浪宠物救助系统25128(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
数据库·vue.js·宠物
吕彬-前端2 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱2 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai2 小时前
uniapp
前端·javascript·vue.js·uni-app
帅比九日3 小时前
【HarmonyOS Next】封装一个网络请求模块
前端·harmonyos