组合式API - provide和inject、Vue3小案例【Vue3】

组合式API - provide和inject

作用和场景:顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
跨层传递普通数据

  1. 顶层组件通过provide函数提供数据 provide('key', 顶层组件中的数据)
  2. 底层组件通过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>

跨层传递方法
顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件中的数据
总结:

  1. provide和inject的作用是什么?
    跨层组件通信
  2. 如何在传递过程中保持数据响应式?
    第二个参数传递ref对象
  3. 底层组件想要通知顶层组件做修改,如何做?
    传递方法,底层组件调用方法
  4. 一颗组件树中只有一个顶层或底层组件吗?
    相对概念,存在多个顶层和底层的关系

Vue3小案例

组合式API - provide和inject、Vue3小案例【Vue3】_第1张图片
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>

你可能感兴趣的:(vue.js,前端,javascript)