父传子
父传子是通过props(组件上自定义的attribute。子组件注册attribute,父组件给这些attribute赋值,子组件通过对应的attribute名称获取对应的值) 来完成组件之间的通信
Props
- 数组用法
- 数组中的字符串就是attribute的名称
<template>
<div class="card-container">
<div class="card-header">
<div class="card-title">{{ title }}</div>
<div v-if="showBackBtn">aaa</div>
</div>
<div class="card-content">
<slot></slot>
</div>
</div>
</template>
<script setup>
const props = defineProps(["title","showBackBtn"])
</script>
<template><ContentCard title="状态修改" :showBackBtn="true"> </ContentCard></template>
<script setup>
import ContentCard from '@/components/admin/ContentCard.vue'
</script>
2. 对象用法
- 可以对传入的内容进行限制(指定传入的attribute的类型,是否必传,默认值)
<template>
<div class="card-container">
<div class="card-header">
<div class="card-title">{{ title }}</div>
<button v-if="showBackBtn" @click="handleBack" class="back-button">
<el-icon :size="18"><Back /></el-icon>返回
</button>
</div>
<div class="card-content">
<slot></slot>
</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
import { Back } from '@element-plus/icons-vue'
const { title, showBackBtn } = defineProps({
title: {
type: String,
required: true,
},
showBackBtn: {
type: Boolean,
default: false,
},
})
const router = useRouter()
const handleBack = () => router.go(-1)
</script>
<template><ContentCard title="状态修改"> </ContentCard></template>
<script setup>
import ContentCard from '@/components/admin/ContentCard.vue'
</script>
非Prop的Attribute
传递给子组件的某些个属性,这些属性不在子组件的props和emits里面
常见class、style、id
- 若组件有单个根节点,非prop的attribute会自动添加到根节点的attribute中(继承)
- 禁用attribute继承和多个根节点情况
- 组件中设置inheritAttrs:false可以禁用根组件自动attribute继承,我们可以在子组件中使用$attrs来访问非Prop的Attribute
<template>
<div class="card-container">
<div class="card-header">
<div class="card-title">{{ title }}</div>
<div v-if="showBackBtn">aaa</div>
</div>
<div :class="$attrs.class">
<slot></slot>
</div>
</div>
</template>
<script setup>
const props = defineProps(["title","showBackBtn"])
</script>
- 若组件有多个根节点且没有显示绑定,此时会报警告,需手动绑定
<template>
<div class="card-header">
<div class="card-title">{{ title }}</div>
<div v-if="showBackBtn">aaa</div>
</div>
<div :class="$attrs.class">
<slot></slot>
</div>
</template>
<script setup>
const props = defineProps(["title","showBackBtn"])
</script>
子传父
- 子组件defineEmits()定义可以触发并且被父组件监听的事件
- 父组件@+子组件定义的事件名监听该事件
- 当子组件使用emit()触发某事件时,父组件监听到该事件被触发,便执行父组件里该事件对应的逻辑
<template>
<div class="child">
<h3>子组件</h3>
<button @click="sendData">向父组件传递数据</button>
</div>
</template>
<script setup>
import { defineEmits } from 'vue'
// 定义可以触发的事件
const emit = defineEmits(['send-message'])
// 子组件发送数据的方法
const sendData = () => {
// 可以是任意类型的数据:字符串、数字、对象等
const message = "Hello 父组件,这是子组件发送的数据!"
const count = 100
// 通过emit触发事件,传递数据给父组件
emit('send-message', message, count)
}
</script>
<template>
<div class="parent">
<h2>父组件</h2>
<p>子组件传递的消息:{{ receivedMessage }}</p>
<p>子组件传递的数字:{{ receivedCount }}</p>
<!-- 引入子组件并监听事件 -->
<ChildComponent @send-message="handleMessage" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
// 父组件用于存储接收的数据
const receivedMessage = ref('')
const receivedCount = ref(0)
// 处理子组件传递过来的数据
const handleMessage = (msg, count) => {
receivedMessage.value = msg
receivedCount.value = count
}
</script>
Tips
- 父传子时,当需要传递 非字符串数据(如布尔值、数字、对象、数组等)时,必须加 :,只有传递纯字符串时可以省略
- 在Vue 3的
<script setup>
语法中,当我们使用defineProps
定义props后,Vue会自动将props解构到当前作用域中,所以我们可以直接使用title
而不是props.title
。 - HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名
<template><ContentCard title="状态修改" :show-back-btn="ture"> </ContentCard></template>
<script setup>
import ContentCard from '@/components/admin/ContentCard.vue'
</script>