「本专栏是我在学习 Vue3 过程中的总结与分享,旨在帮助初学者快速上手 Vue3。由于我也在持续学习中,如果有任何疏漏或错误,欢迎大家在评论区指正,我们一起进步!」
提示:使用该文档学习vue3需要有一些vue和vue2的基础才可以更好的学习噢~~
版权:未经允许,禁止转载!
鼓励:每一次自我怀疑,都是成长的信号,它在提醒你正站在突破的边缘。大胆向前,你的能力远超想象,自信会为你推开成功之门。
————————————————
提示:本章是vue3组件间联系的语法学习,也是相当重要的内容,大家加把劲,就快要学完了!
在Vue3开发中,组件通信是构建复杂应用的核心之一。无论是父子组件间的数据传递,还是跨层级组件的状态共享,掌握高效的通信方式都能让代码更清晰、维护更轻松。Vue3提供了多种通信方式,如props、emit、provide/inject、v-model以及attrs等,每种方式都有其适用场景。本文将带你全面了解这些方法,帮助你在实际开发中灵活运用。
props 向子组件传递数据。示例代码:
Father.vue
<template>
<div class="father">
<h3>父组件h3>
<h4>汽车:{{car}}h4>
<h4 v-if="toy">子给的玩具:{{toy}}h4>
<Child :car = 'car' :sendToy = 'getToy' >Child>
div>
template>
<script setup lang="ts" name="Father">
import { ref } from 'vue';
import Child from './Child.vue'
//数据
let car = ref('奔驰')
let toy = ref('')
//方法
function getToy(value:string){
toy.value = value
}
script>
<style scoped>
.father{
background-color:rgb(165, 164, 164);
padding: 20px;
border-radius: 10px;
}
style>
Child.vue
<template>
<div class="child">
<h3>子组件h3>
<h4>玩具:{{toy}}h4>
<h4>父亲给的车:{{car}}h4>
<button @click="sendToy(toy)">传递给父级玩具button>
div>
template>
<script setup lang="ts" name="Child">
import { ref } from 'vue';
//数据
let toy = ref('奥特曼')
// 用props接收父级传来的数据
defineProps(['car','sendToy'])
script>
<style scoped>
.child{
background-color: skyblue;
padding: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
style>
$emit 触发自定义事件,父组件监听并处理。示例代码:
Father.vue
<template>
<div class="father">
<h3>父组件h3>
<h4 v-show="toy">子级给的数据:{{toy}}h4>
<Child @send-toy="getToy">Child>
div>
template>
<script setup lang="ts" name="Father">
import { ref } from 'vue';
import Child from './Child.vue'
const toy = ref('')
function getToy(value:string){
toy.value = value
}
script>
<style scoped>
.father{
background-color:rgb(165, 164, 164);
padding: 20px;
border-radius: 10px;
}
style>
Child.vue
<template>
<div class="child">
<h3>子组件h3>
<button @click="$emit('send-toy',toy)">点我将数据送给父级button>
div>
template>
<script setup lang="ts" name="Child">
import { ref } from 'vue';
const toy = ref('奥特曼')
// 需要使用数组的形式才可以
let emit = defineEmits(['send-toy'])
script>
<style scoped>
.child{
background-color: skyblue;
padding: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
style>
npm i mitt
新建文件:src\utils\emitters.ts
emitters.ts
// 引入
import mitt from "mitt";
// 调用
// emitter 可以绑定/触发事件
const emitter = mitt()
/*
// 绑定事件
emitter.on('test1', () => {
console.log('test1');
})
// 触发事件
emitter.emit('test1')
// 解绑事件
emitter.off('test1')
// 全部解绑
emitter.all.clear()
*/
// 暴露
export default emitter
实例代码:
Child.vue
<template>
<div class="child">
<h3>子组件h3>
<h4 v-show="toy">叔叔给孩子的玩具:{{toy}}h4>
div>
template>
<script setup lang="ts" name="Child">
import emitter from '@/utils/emitters';
import { onUnmounted, ref } from 'vue';
const toy = ref('')
emitter.on('send-toy',(value:any) => {
toy.value = value
})
// 绑定之后在销毁之后必须把事件解绑了噢!!!
onUnmounted(()=>{
emitter.off('send-toy')
})
script>
<style scoped>
.child{
background-color: skyblue;
padding: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
style>
Uncle.vue
<template>
<div class="uncle">
<h3>叔组件h3>
<button @click="sendToy">点击送给孩子玩具button>
div>
template>
<script setup lang="ts" name="Child">
import emitter from '@/utils/emitters';
import { ref } from 'vue';
// 叔叔用emit方法给孩子送玩具
let toy = ref('娃娃')
function sendToy(){
emitter.emit('send-toy',toy.value)
}
script>
<style scoped>
.uncle{
background-color: orange;
padding: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
style>
Father.vue
<template>
<div class="father">
<h3>父组件h3>
<Child>Child>
<br>
<Uncle>Uncle>
div>
template>
<script setup lang="ts" name="Father">
import { ref } from 'vue';
import Child from './Child.vue'
import Uncle from './Uncle.vue';
script>
<style scoped>
.father{
background-color:rgb(165, 164, 164);
padding: 20px;
border-radius: 10px;
}
style>
示例代码:
Child.vue
<template>
<div class="child">
<input type="text" :value="modelValue" @input="emit('update:modelValue',($event.target).value)" >
div>
template>
<script setup lang="ts" name="Child">
defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
script>
<style scoped>
input{
background-color: skyblue;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
style>
Father.vue
<template>
<div class="father">
<h3>父组件h3>
<Child v-model="username">Child>
div>
template>
<script setup lang="ts" name="Father">
import { ref } from 'vue';
import Child from './Child.vue'
let username = ref('zhangsan')
script>
<style scoped>
.father{
background-color:rgb(165, 164, 164);
padding: 20px;
border-radius: 10px;
}
style>
注意 v-model:ming=“passwad” 这样取的props就不用写modelValue,而是ming 并且修改名字 一个组件上可以绑定多个v-model
props 中声明的属性,可以通过 $attrs 访问。示例代码:
Father.vue
<template>
<div class="father">
<h3>父组件h3>
<h4>a:{{a}}h4>
<h4>b:{{b}}h4>
<h4>c:{{c}}h4>
<h4>d:{{d}}h4>
<Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA">Child>
div>
template>
<script setup lang="ts" name="Father">
import { ref } from 'vue';
import Child from './Child.vue'
function updateA(value:number){
a.value += value
}
let a = ref(1)
let b = ref(2)
let c = ref(3)
let d = ref(4)
script>
<style scoped>
.father{
background-color:rgb(165, 164, 164);
padding: 20px;
border-radius: 10px;
}
style>
Child.vue
<template>
<div class="child">
<h3>子组件h3>
<Grand v-bind="$attrs">Grand>
div>
template>
<script setup lang="ts" name="Child">
import Grand from './Grand.vue';
script>
<style scoped>
.child{
background-color: skyblue;
box-shadow: 0 0 10px black;
border-radius: 10px;
padding: 15px;
}
style>
Grand.vue
<template>
<div class="grand">
<h3>孙组件h3>
<h4>a:{{a}}h4>
<h4>b:{{b}}h4>
<h4>c:{{c}}h4>
<h4>d:{{d}}h4>
<h4>x:{{x}}h4>
<h4>y:{{y}}h4>
<button @click="updateA(6)">点我更改爷爷的Abutton>
div>
template>
<script setup lang="ts" name="grand">
// $attrs实现了defineProps从爷爷到孙子的写法
defineProps(['a','b','c','d','x','y','updateA'])
script>
<style scoped>
.grand{
background-color: orange;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
style>
$refs 直接访问子组件的实例或 DOM 元素。示例代码:
Father.vue
<template>
<div class="father">
<h3>父组件h3>
<h4>父亲有:{{money}}元h4>
<button @click="addBook($refs)">给孩子添加书本button>
<Child ref="c1">Child>
<Daughter ref="d1">Daughter>
div>
template>
<script setup lang="ts" name="Father">
import { ref } from 'vue';
import Child from './Child.vue'
import Daughter from './Daughter.vue';
let money = ref(1000)
let c1 = ref()
let d1 = ref()
// 为儿女的书本每次增加3本
function addBook(refs: any){
for (const key in refs) {
refs[key].book += 3
}
}
script>
<style scoped>
.father{
background-color:rgb(165, 164, 164);
padding: 20px;
border-radius: 10px;
}
style>
Child.vue
<template>
<div class="child">
<h3>儿子组件h3>
<h4>儿子有:{{book}}本书h4>
div>
template>
<script setup lang="ts" name="Child">
import { ref } from 'vue';
let book = ref(3)
defineExpose({book})
script>
<style scoped>
.child{
background-color: skyblue;
box-shadow: 0 0 10px black;
border-radius: 10px;
padding: 15px;
}
style>
Daughter.vue
<template>
<div class="child">
<h3>女儿组件h3>
<h4>女儿有:{{book}}本书h4>
div>
template>
<script setup lang="ts" name="Child">
import { ref } from 'vue';
let book = ref(3)
defineExpose({book})
script>
<style scoped>
.child{
background-color: orange;
box-shadow: 0 0 10px black;
border-radius: 10px;
padding: 15px;
}
style>
$parent 直接访问父组件的实例。示例代码:
Father.vue
<template>
<div class="father">
<h3>父组件h3>
<h4>父亲有:{{money}}元h4>
<Child ref="c1">Child>
div>
template>
<script setup lang="ts" name="Father">
import { ref } from 'vue';
import Child from './Child.vue'
let money = ref(1000)
let c1 = ref()
defineExpose({money})
script>
<style scoped>
.father{
background-color:rgb(165, 164, 164);
padding: 20px;
border-radius: 10px;
}
style>
Child.vue
<template>
<div class="child">
<h3>儿子组件h3>
<h4>儿子有:{{book}}本书h4>
<button @click="expendMoney($parent)">花父亲20块钱button>
div>
template>
<script setup lang="ts" name="Child">
import { ref } from 'vue';
let book = ref(3)
// 儿子花父亲的钱
function expendMoney(parent: any){
parent.money -= 20
}
script>
<style scoped>
.child{
background-color: skyblue;
box-shadow: 0 0 10px black;
border-radius: 10px;
padding: 15px;
}
style>
props 和 emit:适合父子组件之间的单向或简单双向通信。mitt:适合跨组件通信,解耦性强。v-model:适合需要双向绑定的场景。$attrs:适合透传属性或事件。$refs 和 $parent:适合直接操作组件实例,但需谨慎使用,避免过度耦合。根据具体场景选择合适的通信方式,可以让代码更清晰、更易维护!