组件传参
组件间的数据传递,分为很多种方法,各方法的适用情况大致分三种:父组件传递给子组件、子组件给父组件、全局资源。
父组件给子组件
插槽
这是一个一次性的方法,复用了 html 的语法即可传递传递内容给子组件。
<template>
<div class="alert-box">
<strong>This is an Error for Demo Purposes</strong>
<slot /> // [!code highlight]
</div>
</template>
<style scoped>
.alert-box {
/* ... */
}
</style><AlertBox>
Something bad happened.
</AlertBox>插槽可设置默认内容
<button type="submit">
<slot>
Submit <!-- 默认内容 -->
</slot>
</button>具名插槽
组件里面是这样的
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>父组件是这样的用的:
<BaseLayout>
<template v-slot:header>
<!-- header 插槽的内容放这里 -->
</template>
</BaseLayout>v-slot 有对应的简写 #,因此 <template v-slot:header> 可以简写为 <template #header>。其意思就是“将这部分模板片段传入子组件的 header 插槽中”。

若未指定名字,插槽的默认名字其实是default。当子组件内只有一个插槽时,该组件被使用时可省略 <template #default></template>,也就是最简易的用法。但是,当组件内有多个插槽时,可使用 <template #default></template> 插入数据到所有未被赋值的顶层插槽。
条件插槽
先理解一个参数 $slots,这是在具有插槽的组件内,用于表示父组件传入的插槽内容对象。
可以结合其他指令使用,比如结合 v-if 进行条件渲染,当有值时,对应组件才会被渲染:
<template>
<div class="card">
<div v-if="$slots.header" class="card-header">
<slot name="header" />
</div>
<div v-if="$slots.default" class="card-content">
<slot />
</div>
<div v-if="$slots.footer" class="card-footer">
<slot name="footer" />
</div>
</div>
</template>Props 声明(类似函数声明)
在调用组件时,不是按照后端语言的参数位置为定位,而是需要在传递数据(参数)时使用键值对的写法。
用法:子组件使用 defineProps() 函数。
<template>
<ul>
<li v-for="item in list" :key="item.id">
{{item.name}}
</li>
</ul>
</template>
<script setup>
const props = defineProps(['list'])
</script>父组件:
<template>
<div>
<ToDoMain :list="list"/> // [!code highlight]
</div>
</template>
<script setup>
import ToDoMain from './components/ToDoMain.vue';
import { ref } from 'vue';
const list=ref([
{id:1,name:'晨练',status:false},
{id:2,name:'睡觉',status:false},
{id:3,name:'吃早餐',status:false},
{id:4,name:'学习',status:false},
])
</script>可以这样指定需要的数据类型:
const props = defineProps({
foo: String
})provide 和 inject
父组件:使用provide给后代组件提供数据,接收方可以是子组件也可以是孙子组件,可以同时有多个接收方。
import ToDoMain from './components/ToDoMain.vue';
import { ref,provide } from 'vue';
const list=ref([
{id:1,name:'晨练',status:false},
{id:2,name:'睡觉',status:false},
{id:3,name:'吃早餐',status:false},
{id:4,name:'学习',status:false},
])
provide('list',list) 子组件:使用inject()注入函数。
<template>
<ul>
<li v-for="item in todoList" :key="item.id"> // [!code highlight]
{{item.name}}
</li>
</ul>
</template>
<script setup>
import { ref,inject } from 'vue'
const todoList = inject('list')
</script>属性透传(继承)
懒得记了,看这里:https://cn.vuejs.org/guide/components/attrs.html#attribute-inheritance
子组件给父组件
组件事件
子组件:使用defineEmits('事件名')函数和 v-on 内联函数$emit('事件名',被监听变量)创建可被监听的事件。
<template>
<ul>
<li v-for="item in list" :key="item.id">
<div>
<input type="checkbox" class="toggle" v-model="item.status" :id="item.id">
<label :for="item.id">{{item.name}}</label>
<button @click="$emit('todoDelete',item.id)"></button> // [!code highlight]
</div>
</li>
</ul>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps(['list'])
const emit = defineEmits(['todoDelete'])
</script>父组件:同样使用 v-on 或 @ 监听自定义组件事件。
<template>
<div>
<ToDoMain :list="list" @todo-delete="todoDelete"/> // [!code highlight]
</div>
</template>
<script setup>
import ToDoMain from './components/ToDoMain.vue';
import { ref,provide } from 'vue';
const list=ref([
{id:1,name:'晨练',status:false},
{id:2,name:'睡觉',status:false},
{id:3,name:'吃早餐',status:false},
{id:4,name:'学习',status:false},
])
// [!code highlight: 4]
const todoDelete = (id) => { // 可同时使用形参接收子组件传来的数据。
list.value=list.value.filter(item=>item.id!==id)
}
const add=(name)=>{
list.value.push({
id:list.value.length+1,
name,
status:false
})
}
</script>作用域插槽
其实就是将 props 作为插槽传递,与 Props 不同的是,这是子组件将数据传递给父组件。
子组件ChildComponent.vue:
<template>
<div>
<h2>子组件</h2>
<!-- 在插槽中传递数据 -->
<slot :user="user" :age="age"></slot> // [!code highlight]
</div>
</template>
<script setup>
import { ref } from 'vue'
const user = ref('张三')
const age = ref(18)
</script>父组件ParentComponent.vue:
<template>
<div>
<h1>父组件</h1>
<ChildComponent> // [!code highlight:7]
<!-- 使用v-slot接收子组件传递过来的数据 -->
<template v-slot="slotProps">
<p>从子组件接收到的用户: {{ slotProps.user }}</p>
<p>从子组件接收到的年龄: {{ slotProps.age }}</p>
</template>
<!-- 也可以解构赋值
<template v-slot="{ user, age }">
<p>从子组件接收到的用户: {{ user }}</p>
<p>从子组件接收到的年龄: {{ age }}</p>
</template>
-->
</ChildComponent>
</div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue'
</script>