最全!Vue3组件通信方式

124 阅读1分钟

我正在参加「掘金·启航计划」
在开发中大型项目时,很多场景得通过组件传值来解决,vue3相对于vue2组件间通信的方式还是有很大变化的。文中只列举最基础的一些方法,具体多种用法可以通过vue官网查看。

父子组件通信

在vue2中,可以通过$attrs / $listeners 来进行通信,这种方式在vue3已经移除了

props/emits

父-->子

<!--父-->
<template>
  <child :name="name"/>
</template>
<script lang='ts' setup>
import Child from './child.vue'
const name = 'nexusfeng'
</script>
<!--子-->
<template>
  {{name}}
</template>
<script lang='ts' setup>
const props = defineProps([
  'name'
])
</script>

子-->父

<!--父-->
<template>
  <child @update-name="updateName"/>
</template>
<script lang='ts' setup>
import Child from './child.vue'
const updateName = (args) => {
  //...
}
</script>
<!--子-->
<template>
  ...
</template>
<script lang='ts' setup>
const emit = defineEmits(['updateName'])
emit('updateName', 'Feng')
</script>

v-model/emits

父-->子

<!--父-->
<template>
  <child 
  v-model:name="name"
  v-model:sex="sex"
  />
</template>
<script lang='ts' setup>
import Child from './child.vue'
</script>
<!--子-->
<template>
  ...
</template>
<script lang='ts' setup>
const props = defineProps([
  'name',
  'sex'
])
</script>

子-->父

<!--父-->
<template>
  {{name}}
  <child v-model:name='name'/>
</template>
<script lang='ts' setup>
import {ref} from 'vue'
import Child from './child.vue'
const name = ref('')
</script>
<!--子-->
<template>
  ...
</template>
<script lang='ts' setup>
const emit = defineEmits(['update:name'])
emit('update:name', 'Feng')
</script>

ref/emits

父组件可以通过子组件的ref属性操作子组件的数据或者调用子组件方法

<!--父-->
<template>
  <child ref="child"/>
</template>
<script lang='ts' setup>
import Child from './child.vue'
const child = ref<HTMLElement>(null)
child.value.onLoad()
child.value.name = 'child'
</script>
<!--子-->
<template>
  {{name}}
</template>
<script lang='ts' setup>
const name = ref('Tom')
const onLoad = () => {
  console.log('father')
}
</script>

爷孙组件通信

provide/inject

A通过provide向A.A.A传值,A.A.A通过inject触发A的事件,provide并不是响应式的,如果想要响应式,得传入响应式数据

<!--A-->
<script lang='ts' setup>
import { provide } from 'vue'
// 传入响应式数据
// const name = ref('nexusfeng')
const name = 'nexusfeng'
// 基础数据类型也能响应,改变值时需要重新provide
provide('name', ():string => name)
</script>
<!--A.A.A-->
<script lang='ts' setup>
import { inject } from 'vue'
// 响应式数据
// const name = inject('name') || ''
const name = inject('name')
name()
</script>

注意基础数据类型的写法,如果要响应,得重新provide

全局组件通信(兄弟组件通信推荐此方法)

BUS

vue3移除了$on$off$once,可以使用第三方库来实现mitttiny-emitter

Vuex

vuex的用法与vue2中的并无太大差别

import { createApp } from 'vue'
import { createStore } from 'vuex'

const store = createStore({
  state:{
    return {
      name: 'feng'
    }
  },
  mutations: {},
  actions:{},
  modules:{}
})
<!--组件中使用-->
<template>
  {{store.state.name}}
</template>
<script lang='ts' setup>
import { useStore } from 'vuex'
const store = useStore()
</script>

Pinia

Pinia相对于vuex,去除了mutations,也就是没有了同步操作和异步操作的区分,方便很多,对ts的支持也很好

//main.ts
import {createApp} from 'vue'
import {createPinna} from 'pinia'
import App from '@/App.vue'

createApp(App)
  .use(createPinia())
  .mount('#app')
// src/stores/index.ts
import {defineStore} from 'pinia'
export const useStore = defineStore('main', {
  state: () => ({
    name: 'feng'
  })
})
<!--组件中使用-->
<template>
  {{store.name}}
</template>
<script lang='ts' setup>
import { useStore } from '@/store'
const store = useStore()
</script>