(vue官网:查看)
(vue位于Github的地址:查看)
这篇文章的目的是让大家知道有这些方法可以用,所以不会深挖,接下来讲解的每种通信方式我都会附带一个简单的demo。
觉得有帮助的话别忘了收藏
开始
Vue3的12种组件通信方式(下面是讲解顺序)
- Props
- emits
- model
- slot
- provide / inject
- bus
- getCurrentInstance
- expose / ref
- Non-Props
- Vuex
- Pinia
- mitt.js
Props / emits
-
- 在 < script setup> 中必须使用 defineProps API 来声明 props和emits
-
- 下面是使用Props与emits的通信示例(Vue官网中Props的解读)
/父组件
<template>
<b-Vue :msg="props父传子的消息" @changeMsg="changeMessage" />
</template>
<script setup>
import bVue from './components/b.vue'
function changeMessage(data) {
//data:'emits子传父的消息'
}
</script>
/子组件b.vue
<template>
<div>
<div @click="handleClick"> {{ msg }} <div> //msg: 'props父传子的消息'
</div>
</template>
<script setup>
const props = defineProps({
msg: {
type: String,
default: ''
}
})
// 注册一个自定义事件名,向上传递时告诉父组件要触发的事件。
const emit = defineEmits(['changeMsg'])
function handleClick() {
emit('changeMsg', 'emits子传父的消息')
}
</script>
v-model / emits
-
v-model 是 一个语法糖,通过Vue3的文档可以发现,这个指令的用法发生了一定的变化。在之前,xxxx.sync与之是很相似的,如今.sync指令已经被废除了,而是统一使用v-model这个指令。
-
v-model在组件身上使用
-
相当有给子组件传递props[modelValue] = 10000
-
相当于给子组件绑定自定义事件update:modelValue
-
-
下面是使用v-model 与emits的通信示例 ( Vue官网中对于v-model的描述 )
/父组件
// Parent.vue
<template>
<b-Vue v-model:msg1="message1" v-model:msg2="message2" />
</template>
<script setup>
import { ref } from 'vue'
import bVue from './components/b.vue'
const message1 = ref('父传子1')
const message2 = ref('父传子2')
</script>
// 子组件
<template>
<div><button @click="send1">修改msg1</button> {{msg1}}</div>
<div><button @click="send2">修改msg2</button> {{msg2}}</div>
</template>
<script setup>
import { ref } from 'vue'
// 接收参 // 接收父组件使用 v-model 传进来的‘单’个值,必须用 modelValue 这个名字来接收
const props = defineProps({
msg1: String,
msg2: String
})
必须用 update:参数||modelValue 这个格式来通知父组件修改值
const emit = defineEmits(['update:send1', 'update:send2'])
function send1() {
emit('update:msg1', 'GOA1')
}
function send2() {
emit('update:msg2', 'GOA2')
}
</script>
slot插槽
- 插槽可以理解为传一段 HTML 片段给子组件。子组件将 元素作为承载分发内容的出口。
- 插槽的基础用法非常简单,只需在 子组件 中使用 标签,就会将父组件传进来的 HTML 内容渲染出来。
- 下面是slot进行通信的示例 (Vue官网关于slot的说明)
/父组件
<template>
<!-- v-slot="{scope}" 获取子组件传上来的数据 -->
<!-- :list="list" 把list传给子组件 -->
<b-Vue v-slot="{scope}" :list="list">
<div>
<div> {{ scope.id}}</div>
<div>{{ scope.text}}</div>
<hr>
</div>
</b-Vue>
</template>
<script setup>
import { ref } from 'vue'
import bVue from './components/b.vue'
const list = ref([
{ id: '1', text: '1'},
{ id: '2', text: '1'},
{ id: '3', text: '1'},
])
</script>
/子组件
<template>
<div>
<!-- 用 :scope="item" 返回每一项 -->
<slot v-for="item in list" :scope="item" />
</div>
</template>
<script setup>
const props = defineProps({
list: {
type: Array,
default: () => []
}
})
</script>
provide / inject
- 遇到父孙之间传值, props 和 emit 的方式会显得比较笨拙。这时就可以用 provide 和 inject 了。
- provide 是在父组件里使用的,可以往下传值。
- inject 是在子(后代)组件里使用的,可以网上取值。
- 无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。
- 下面是provide / inject进行实践的示例(Vue官网对provide / inject的描述)
/父
<template>
<b-Vue></b-Vue>
</template>
<script setup>
import { ref, provide, readonly } from 'vue'
import bVue from './components/b.vue'
const name = ref('provide+readonly传的字')
const msg = ref('provide传的字')
// 使用readonly可以让子组件无法直接修改,需要调用provide往下传的方法来修改
provide('name', readonly(name))
provide('msg', msg)
provide('changeName', (value) => {
name.value = value
})
</script>
/子
<template>
<div>
<div>msg: {{ msg }}</div>
<div>name: {{name}}</div>
<button @click="handleClick">修改</button>
</div>
</template>
<script setup>
import { inject } from 'vue'
const name = inject('name', '默认值') //provide传的字
const msg = inject('msg')
const changeName = inject('changeName')
function handleClick() {
// 正确的方式
changeName('虎躯一震')
// 因为 msg 没被 readonly 过,所以可以直接修改值
msg.value = '世界'
}
</script>
useAttrs
- vue3框架提供了一个方法useAttrs方法,可以获取到组件身上的属性和事件,换个说法,useAttrs的功能于props的功能很类似,都是父组件传递数据给子组件。
- 如果使用了props和useAttrs同时接收数据,props的优先级比useAttrs高
- 下面为使用attrs进行通信的实践
/父
<template>
<b-Vue type="primary" title="名字" ></b-Vue>
</template>
<script setup lang="ts">
import bVue from './b.vue';
const handleEvent = () => {}
const handle = () => {}
</script>
/子
<template>
<div>
子组件:{{ attrs.title }}
</div>
</template>
<script setup lang="ts">
// 引入useAttrs方法:获取组件(attrsSon)身上的属性和事件
import { useAttrs } from 'vue';
// 此方法会返回一个对象
let attrs = useAttrs()
console.log('attrs',attrs); //组件身上的属性和事件
</script>
eventBus
- 如果你刚开始使用Vue3,很可能会发现,原本用得得心应手的eventBus突然不灵了,因为Vue3不再提供$on与emit函数,Vue实例不再实现事件接口。Vue 官方推荐使用 mitt 或 tiny-emitter。,或者自己手撸一个事件类
- 这个vue实现eventBus的效果其实多种,我就不舞刀弄枪了,这里推荐一篇写的蛮好的博客(下面链接)
- Vue 3 中如何优雅的使用eventBus(事件总线)
getcurrentinstance
- getcurrentinstance 是 vue 提供的一个方法,支持访问内部组件实例。
- getCurrentInstance 只暴露给高阶使用场景,典型的比如在库中。
- 强烈反对在应用的代码中使用 getCurrentInstance。请不要把它当作在组合式 API 中获取 this 的替代方案来使用。
- getCurrentInstance 只能在 setup 或生命周期钩子中调用。
- 只有在 development,即开发环境下才能获取到当前组件的实例,换句话说就是这个方法只是在开发环境下用于调试使用的;(适合在开发组件库的情况下使用,不适合日常业务开发中使用 )
- 有兴趣的话可以去钻研一下,我这里就简单介绍下
import { getCurrentInstance } from 'vue'
let num= null;
num = getCurrentInstance
console.log(num) //开发环境下可以获取到组件实例
expose / ref
-
子组件可以通过 expose 暴露自身的方法和数据。
-
父组件通过 ref 获取到子组件并调用其方法或访问数据。
-
使用ref可以直接得到子组件的定义值,但要注意:在父组件要使用getCurrentInstance得到this,在子组件使用defineExpose暴露变量。
/父拿到子的数据
<template>
<div>{{ msg }}</div>
<button @click="callChildFn">调用子组件的方法</button>
<b-Vue ref="com" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import bVue from './components/b.vue'
const com = ref(null)
const msg = ref('')
onMounted(() => {
// 在加载完成后,将子组件的 message 赋值给 msg
msg.value = com.value.message
})
function callChildFn() {
// 调用子组件的 changeMessage 方法
com.value.changeMessage('父改变参')
// 重新将 子组件的message 赋值给 msg
msg.value = com.value.message
}
</script>
/子
<template>
<div>{{ message }}</div>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('我是子的参')
function changeMessage(data) {
message.value = data
}
使用 defineExpose 向外暴露指定的数据和方法
defineExpose({
message,
changeMessage
})
</script>
Non-Props
-
Non-Props 就是 非 Prop 的 Attribute。(Vue官网中的描述)
-
意思是在子组件中,没使用 prop 或 emits 定义的 attribute,可以通过 $attrs 来访问。常见的有 class 、style 和 id。
/父
<template>
<b-Vue msg="传子的数据" name="父亲" />
</template>
<script setup>
import { ref } from 'vue'
import bVue from './components/b.vue'
</script>
<template>
<div :message="$attrs.msg">只绑定指定值</div>
<div v-bind="$attrs">全绑定</div>
</template>
/有兴趣可以上手一下
Vuex
- Vuex和Pinia是Vue3中的状态管理工具,使用这两个工具可以轻松实现组件通信,由于这两个工具功能比较强大,这里就不做展示了,具体可以查阅文档 (改天有空补上)
休息一下先 等会儿写