(vue官网:查看)
(vue位于Github的地址:查看)
这篇文章的目的是让大家知道有这些方法可以用,所以不会深挖,接下来讲解的每种通信方式我都会附带一个简单的demo。
觉得有帮助的话别忘了收藏
开始
Vue3的12种组件通信方式(下面是讲解顺序)
Props / emits
/父组件
<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插槽
/父组件
<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
/父
<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
/父
<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
getcurrentinstance
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
休息一下先 等会儿写