Provide/Inject
通常父组件给子组件传递数据时,使用props的方式,如果是比较深得组件嵌套的话,就需要逐层的进行传递,这样的话,可能会比较麻烦
vue提过了一个api去简化这个操作
provide 可以在祖先组件中指定我们想要提供给后代组件的数据或方法,而在任何后代组件中,我们都可以使用 inject 来接收 provide 提供的数据或方法。
祖先组件
<script setup lang="ts">
// 采用provide的方式,将祖先组件数据传递给子组件
import { provide,ref } from 'vue'
import A from "./components/A.vue"
const count = ref(0)
provide('count',count)
</script>
<template>
<div>
<h1>{{count}}</h1>
</div>
<A></A>
</template>
<style scoped>
</style>
在需要用到这个ref数据的时候,只需要inject接受即可
也可以采用readonly防止数据被更改
provide('count',readonly(count))
后代组件
<script setup lang="ts">
import {inject} from "vue";
const data = inject('count')
</script>
<template>
<div class="container">
<div>
<span>请输入:</span>
<input type="text" v-model="data">
</div>
</div>
</template>
<style scoped>
.container {
width: 500px;
height: 500px;
background-color: #ccc;
border: 1px solid grey;
margin: 0 auto;
}
.header {
height: 50px;
background-color: #eee;
border: 1px solid grey;
}
.body {
height: 400px;
background-color: #ddd;
border: 1px solid grey;
}
.footer {
height: 50px;
background-color: #eee;
border: 1px solid grey;
}
</style>
兄弟组件传参
有两种方式
1. 借助父组件传参
A组件提交一个事件用来传递参数,父组件接受这个事件拿到值,通过props的方式再转给B组件
案例:
父组件
<script setup lang="ts">
// 借助父组件,进行兄弟组件之间的通信
import A from './components/A.vue'
import B from './components/B.vue'
import {ref,Ref} from 'vue'
const title:Ref<string> = ref('hello')
const handleUpdate = (data:string):void => {
title.value = data
}
</script>
<template>
<A @update="handleUpdate"></A>
<B :title="title"></B>
</template>
<style scoped>
</style>
A组件
<script setup lang="ts">
import { ref } from 'vue'
const data = ref('')
// let emit = defineEmits<{
// (e: 'update', value: string): void
// }>()
const emit = defineEmits(['update'])
</script>
<template>
<div class="container">
<div>
<span>请输入:</span>
<input type="text" v-model="data">
</div>
<button @click="emit('update', data)">提交</button>
</div>
</template>
<style scoped>
</style>
B组件
<script setup lang="ts">
// 使用defineProps的js和ts写法
defineProps<{
title: string
}>()
// const props = defineProps({
// title:{
// type:String,
// default:''
// }
// })
</script>
<template>
<div class="context">
<h1>我是b组件</h1>
<div>
<span>{{title}}</span>
</div>
</div>
</template>
<style scoped>
</style>
2. Event bus
在vue3中$on,$off 和 $once 实例方法已被移除,组件实例不再实现事件触发接口,因此大家熟悉的EventBus便无法使用了。然而我们习惯了使用EventBus,对于这种情况我们可以使用Mitt库(其实就是发布订阅模式的设计)
安装:
npm install mitt -S
使用:
再main.ts中
import { createApp } from 'vue'
import App from './App.vue'
import "animate.css"
import Card from "./components/Card.vue";
import mitt from 'mitt';
const emitter = mitt();
declare module "vue" {
export interface ComponentCustomProperties {
$Bus: typeof emitter
}
}
const app = createApp(App)
app.config.globalProperties.$Bus = emitter; // 全局事件总线
app.component("Card",Card).mount('#app')
A组件通过emit派发事件
<script setup lang="ts">
import { ref,getCurrentInstance } from 'vue'
const data = ref('')
const instance = getCurrentInstance()
function handleEmit() {
instance?.proxy?.$Bus.emit('submit', data.value)
}
</script>
<template>
<div class="container">
<div>
<span>请输入:</span>
<input type="text" v-model="data">
</div>
<button @click="handleEmit">提交</button>
</div>
</template>
<style scoped>
.container {
width: 500px;
height: 500px;
background-color: #ccc;
border: 1px solid grey;
margin: 0 auto;
}
.header {
height: 50px;
background-color: #eee;
border: 1px solid grey;
}
.body {
height: 400px;
background-color: #ddd;
border: 1px solid grey;
}
.footer {
height: 50px;
background-color: #eee;
border: 1px solid grey;
}
</style>
B组件通过on去接受
<script setup lang="ts">
// 使用defineProps的js和ts写法
import {ref,getCurrentInstance} from "vue";
const title = ref('我是b组件的title')
const instance = getCurrentInstance()
// 接受兄弟组件通过mitt传递过来的数据
instance?.proxy?.$Bus.on('submit',(val:string)=>{
title.value = val
})
</script>
<template>
<div class="context">
<h1>我是b组件</h1>
<div>
<span>{{title}}</span>
</div>
</div>
</template>
<style scoped>
.context {
width: 500px;
height: 300px;
background-color: #ccc;
border: 1px solid grey;
margin: 0 auto;
}
h1 {
text-align: center;
}
</style>
3使用方法通过emit派发, on 方法添加事件,off 方法移除,clear 清空所有
也可以通过on('*')的方式监控所有组件