组合式API - provide和inject
作用和场景:顶层组件向任意的底层组件传递数据和方法
,实现跨层组件通信
跨层传递普通数据
- 顶层组件通过
provide函数提供
数据provide('key', 顶层组件中的数据)
- 底层组件通过
inject函数获取
数据const message = inject('key')
跨层传递响应式数据
在调用provide函数时,第二个参数设置为ref对象
顶层组件:provide('app-key', ref对象)
底层组件:const message = inject('app-key')
<template>
<div class="page">
顶层组件
<RoomMsgItem/>
</div>
</template>
<script setup>
import {provide, ref} from 'vue'
import RoomMsgItem from './room-msg-item.vue'
//组件嵌套关系:RoomPage -> RoomMsgItem ->RoomMsgComment
// 1.顶层组件提供数据
provide('data-key', 'this is room data')
// 传递响应式的数据
const count = ref(0)
prodive('count-key', count)
setTimeout(()=>{
count.value = 100
}, 3000)
</script>
<style>
</style>
<script setup>
import { inject } from "vue";
// 2.接收数据
const roomData = inject('data-key')
//接收响应式数据
const countData = inject('count-key')
</script>
<template>
<div class="comment">
底层组件
<div>
来自顶层组件中的数据为:{{ roomData }}
</div>
<div>
来自底层组件中的数据为:{{ counntData }}
</div>
</div>
</template>
<style>
</style>
跨层传递方法
顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件中的数据
总结:
- provide和inject的作用是什么?
跨层组件通信 - 如何在传递过程中保持数据响应式?
第二个参数传递ref对象 - 底层组件想要通知顶层组件做修改,如何做?
传递方法,底层组件调用方法 - 一颗组件树中只有一个顶层或底层组件吗?
相对概念,存在多个顶层和底层的关系
Vue3小案例
App.vue
<script setup>
import { onMounted, ref } from 'vue'
import Edit from './components/Edit.vue'
import axios from 'axios'
// TODO: 列表渲染
// 思路:声明响应式list -> 调用接口获取数据 -> 后端数据赋值给list -> 绑定到table组件
const list = ref([])
const getList = async () => {
// 接口调用
const res = await axios.get('./list')
// 交给list
list.value = res.data
}
onMounted(()=>getList())
// TODO: 删除功能
//思路:获取当前行的id -> 通过id调用删除接口 -> 更新最新的列表
const onDelete = async (id) => {
console.log(id);
await axios.delete(`/del/${id}`)
getList()
}
// TODO: 编辑功能
// 思路:打开弹框 -> 回填数据 -> 更新数据
// 1.打开弹框(获取到子组件实例 调用方法或者修改属性)
// 2.回填数据(调用详情接口 / 当前行的静态数据)
const editRef = ref(null)
const onEdit = (row)=>{
editRef.value.open(row)
}
</script>
<template>
<div class="app">
<el-table :data="list">
<el-table-column label="ID" prop="id"></el-table-column>
<el-table-column label="姓名" prop="name" width="150"></el-table-column>
<el-table-column label="籍贯" prop="place"></el-table-column>
<el-table-column label="操作" width="150">
<template #default="{row}">
<el-button type="primary" @click="onEdit(row)" link>编辑</el-button>
<el-button type="danger" @click="onDelete(row.id)" link>删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<Edit ref="editRef" @on-update="getList"/>
</template>
<style scoped>
.app {
width: 980px;
margin: 100px auto 0;
}
</style>
components/Edit.vue
<script setup>
// TODO: 编辑
import axios from 'axios'
import { ref } from 'vue'
// 弹框开关
const dialogVisible = ref(false)
// 准备form
const form = ref({
name: '',
place: '',
id: ''
})
const open = (row)=>{
console.log(row);
form.value.name = row.name
form.value.place = row.place
form.value.id = row.id
dialogVisible.value = true
}
defineExpose({
open
})
// 更新
const emit = defineEmits(['on-update'])
const onUpdate = async ()=>{
// 1.收集表单数据 调用接口
await axios.patch(`/edit/${form.value.id}`, {
name: form.value.name,
place: form.value.place,
})
// 2.关闭弹框
dialogVisible.value = false
// 3.通知父组件做列表更新
emit('on-update')
}
</script>
<template>
<el-dialog v-model="dialogVisible" title="编辑" width="400px">
<el-form label-width="50px">
<el-form-item label="姓名">
<el-input placeholder="请输入姓名" v-model="form.name"/>
</el-form-item>
<el-form-item label="籍贯">
<el-input placeholder="请输入籍贯" v-model="form.place"/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="onUpdate">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<style scoped>
.el-input {
width: 290px;
}
</style>