Vue3 项目中使用动态组件
需求描述
根据上图,大致要实现的功能为按照左侧的进度菜单,填写每一个步骤中的表单信息,填写完成后,点击下一步或者切换左侧的菜单,可以保存当前页面的数据。
初次实现方式
<div class="online-card box">
<div
v-if="isShowSiderBar"
class="sider"
:class="{ 'sider-80': curStatus === 1 }"
>
左侧菜单
</div>
<div class="main-content">
<router-view></router-view>
</div>
</div>
遇到的问题
在第一个页面【矫治完成】,保存调用接口A, 成功保存数据后,接口会生成一个ID。 在第二个页面【牙齿模型】,调用接口B需要将ID作为参数。此刻问题来了,就是要如何解决这个ID传给第二个页面呢? 刚开始我想到的是借助vuex,但是切换菜单的时候,路由发生变化, 对应页面会发生刷新,那vuexStore 中的数据也将不存在。于是我就利用了浏览器缓存sessionStorage 把这个ID 存下来,但是由于存在新增和编辑的不同场景,要去控制这个ID的准确性就变的复杂,也导致了在测试过程中出现bug。
最终解决方案- 引入动态组件
<div class="online-card box">
<div
v-if="isShowSiderBar"
class="sider"
:class="{ 'sider-80': curStatus === 1 }"
>
左侧菜单
</div>
<div class="main-content">
<router-view v-slot="{ Component }">
<component
:is="Component"
:temporary-save="temporarySave"
@update="updateTemporarySave"
/>
</router-view>
</div>
</div>
interface TemporarySaveProvide {
saveFn?: (isSubmit: boolean) => Promise<boolean>
seqId?: string
readonly caseMainSeqId: string
btnDisabled?: boolean
teethSaved?: boolean
}
const temporarySave = reactive<TemporarySaveProvide>({
saveFn: async (isSubmit: boolean) => false,
seqId: route.query.endCaseId as string,
caseMainSeqId: route.params.seqId as string,
btnDisabled: true || undefined,
teethSaved: false
})
// 提供一个方法供子组件来更新公共数据temporarySave
const updateTemporarySave = (v: Partial<TemporarySaveProvide>) => {
Object.assign(temporarySave, v)
}
// 保存方法
const save = async () => {
if (temporarySave.saveFn) {
let isSubmit = hiddenDown.value
await temporarySave.saveFn(isSubmit)
if (isSubmit) {
router.push({
path: `/caseDetail/${temporarySave.caseMainSeqId}`
})
}
}
}
通过定义一个temporarySave对象,将需要在不同的步骤页面中使用的公有数据,以及每个页面中的保存方法saveFn都抽取出来,方便统一调度。 子组件通过props来接收所有的
const props = defineProps<{
temporarySave: TemporarySaveProvide
}>()
const emit = defineEmits<{
(e: 'update', temporarySave: Partial<TemporarySaveProvide>): void
}>()
通过以上的处理后,还需要注意一个问题,router-view 上不能设置key, 不然组件不会被强制复用,导致temporarySave的值被初始化了
转载自:https://juejin.cn/post/7251795787185111095