likes
comments
collection
share

Vue3 项目中使用动态组件

作者站长头像
站长
· 阅读数 34

需求描述

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
评论
请登录