vue3组件间的通讯方式

在vue3中我们可以用很多方式来实现父与子、子与父、兄弟与兄弟等不同组件的通信。接下来我会展示常用的几种通信方式以及他们各自的特点和使用细节。

props传递

props是最常见的,父组件在调用子组件时通过绑定变量向子组件传递数据。

javascript 复制代码
// parent.vue
<template>
  <Child :msg="message" :count="count" />
</template>

<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const message = ref('Hello from Parent')
const count = ref(0)
</script>
javascript 复制代码
// child.vue
<template>
  <div>
    <p>消息: {{ msg }}</p>
    <p>数量: {{ count }}</p>
  </div>
</template>

<script setup>
defineProps({
  msg: String,
  count: Number
})
</script>

特点:只能父向子传递配置、数据、状态等,不能子向父传递。

使用细节:需要在defineProps里进行变量的声明才能使用。直接解构props没有响应式,需要用toRefs()

自定义事件

自定义事件(defineEmits)的方式可以实现子向父组件传递数据,自定义事件有很多变式写法,此处只演示最简单的使用方法,便于理解中心思想。

javascript 复制代码
// parent.js
<template>
  <p>{{ message }}</p>
  <Child @updateMsg=update />
</template>

<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const message = ref('Hello from Parent')
const update = (val) => {
    message.value = val
}
</script>
javascript 复制代码
// child.js
<template>
  <div>
    <input :value @update=update></input>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const emit = defineEmits(['update-msg']) 
const msg = ref('Hello from child')
const update = (e) => {
    msg.value = e.target.value
    emit('update-msg', msg.value)
}
</script>

特点:自定义事件是通过调用defineEmits显式声明抛出一个父组件监听的事件来实现更新父组件自身的变量。

使用细节:vue3废除了 <math xmlns="http://www.w3.org/1998/Math/MathML"> o n 和 on和 </math>on和emit, 转而用defineEmits来实现自定义事件。 在使用时需要先在调用子组件时声明自定义事件名才能在子组件中进行抛出。

provide和inject

provide和inject适用于祖先组件往后代组件传递数据,可以避免层层props传递。

javascript 复制代码
// parent.js
<template>
  <p>{{ message }}</p>
  <Child @updateMsg=update />
</template>

<script setup>
import { provide, ref } from 'vue'
import Child from './Child.vue'

const message = ref('Hello from Parent')
provide('message', message)
</script>
javascript 复制代码
// child.js
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
import { inject } from 'vue'

const message = inject('message')
</script>

特点:provide/inject可以不用层层传递,在祖先组件进行一次provide声明后续的后代组件都可以通过inject进行调用。

注意事项:在vue3中provide和inject在使用前都需要进行import引入, provide上传的变量如果是用的ref声明,那么子组件更新provide,父组件inject的变量值也会更新。

vuex

vue3不建议使用vuex,但是vuex的作为很常见的设计思想还是有必要进行了解。

使用vuex需要先新建一个store文件夹,然后在文件夹下新建一个index.js文件作为store初始化文件

javascript 复制代码
// store/index.js
import {createStore } from 'vuex'

const selfStore = createStore({
    state() { //变量声明
        return {
            message: 'hello vuex'
        }
    },
    mutations: { // 实际上执行变量操作的部分,该部分是同步的
        UPDATE_MESSAGE(state, payload){
            state.message = payload
        }
    },
    actions: { //也能实现对变量的操作,本质上是通过commit来借助
    //mutations来实现对变量的操作,是异步的
        updatedMessage({commit}, payload){
            commit('UPDATE_MESSAGE', payload)
        }
    },
    getters: { //变量的getter接口,通过调用getters可以获得store内部变量
        message: state => state.message
    }
})

export default selfStore

然后在main.js文件中通过app.use()挂载store

javascript 复制代码
import { createApp } from 'vue'
import selfStore from '../src/store'
import parent from '../src/components/communication/parent.vue'
import child from '../src/components/communication/child.vue'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(router)
app.use(selfStore)

app
.component('parent', parent)
.component('child', child)

app.mount('#app')

在父子组件中分别进行调用store实现子组件向父组件通讯效果

javascript 复制代码
// parent.js
<template>
  <p>{{ message }}</p>
  <Child />
</template>

<script setup>
import { ref } from 'vue'
import { useStore } from 'vuex'
import Child from './Child.vue'

const store = useStore()
const message = computed(() => store.getters.message)
</script>
javascript 复制代码
// child.js
<template>
  <div>
    <input :value=msg @change=changeMsg />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useStore } from 'vuex'

const msg = ref('this is child')
const store = useStore()
const changeMsg = (e) => {
    msg.value = e.target.value
    store.dispatch('updatedMessage', e.target.value)
}
</script>

特点:vuex也是经过一次声明就可以在多个组件中进行调用,不用层层传入。在声明store时就已经声明了变量的初始化、修改、获取等所有行为,在组件使用时不用重新声明。

注意事项:在使用vuex时我们需要手动引入createStore和useStore。vuex的设计思想是单一数据源,但是也可以设置多个store,只是需要在一个js文件里进行声明。在更新数据时建议使用actions来更新数据。

在调用数据是需要用computed对store的变量进行响应式赋值,如果直接进行赋值不通过computed,那么变量不具备响应式。

pinia

pinia是vux推荐的store管理库,和vuex不同的是pinia的设计理念就是为了实现多store情况。

在创建vue3项目时会自动创建一个stores文件夹,我们所有的store文件都放入其中进行管理。

pinia的store有两种写法,一种是传统的声明state、actions、getters的选项式写法,一种是省略state、actions、getters的组合式写法,本文中演示更简单的组合式。

javascript 复制代码
// stores/counter.js
import {defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})

然后在main.js文件中通过app.use()挂载pinia

javascript 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import parent from '../src/components/communication/parent.vue'
import child from '../src/components/communication/child.vue'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(router)
app.use(createPinia())

app
.component('parent', parent)
.component('child', child)

app.mount('#app')

在父子组件中分别进行调用pinia实现子组件向父组件通讯效果

javascript 复制代码
// parent.js
<template>
  <p>{{ counterStore.doubleCount }}</p>
  <Child />
</template>

<script setup>
import { ref } from 'vue'
import { useCounterStore } from '../../stores/counter'
import Child from './Child.vue'

const counterStore = useCounterStore()
</script>
javascript 复制代码
// child.js
<template>
  <div>
    <button @click="buttonClick">{{ counterStore.doubleCount }}</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useCounterStore } from '../../stores/counter'

const buttonClick = () => {
    counterStore.increment()
}
</script>

特点: pinia支持多个store,每个store单独存放在一个js文件里并通过export进行导出,在需要使用时可以直接通过import进行导入就可以进行使用。和vuex不同的是,pinia的store由pinia直接进行管理,

注意事项:在使用pinia时要注意选项式和组合式语法不能同时在一个store中进行使用。pinia自身的state就具备响应式但如果将state里的变量赋给组件中的变量,也需要进行computed修饰使其具有响应式。

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax