vue3中使用keep-alive

352 阅读1分钟

需求:【详情页】返回【列表页】需缓存状态(分页,查询条件),其他页进入【列表页】不缓存

1、在路由表中设置meta中添加keepAlive标识

   // 列表页
  {
    path: '/review-record-info',
    name: 'reviewRecordInfo',
    component: () => import('../views/reviewRecordInfo.vue'),
    meta: {
      keepAlive: true,
    },
  },
  // 详情页
  {
    path: '/review-record-detail',
    name: 'reviewRecordDetail',
    component: () => import('../views/reviewRecordDetail.vue'),
    meta: {
      keepAlive: true,
    },
  }

2、列表页中添加路由拦截、并添加钩子函数

// views/reviewRecordInfo.vue 列表页

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  beforeRouteEnter(to, from, next) {
    // 判断是否是详情页返回
    if (from.path == '/review-record-detail') {
      to.meta.isBack = true
    } else {
      to.meta.isBack = false
    }
    next()
  },
})
</script>
<script setup lang="ts">
import { ref, onMounted, onActivated, onDeactivated } from 'vue'

const { pagination } = usePagination()
const [formData, change] = useListParam(form)
const { listData, refreshData, selection } = useDataList({
  listApi: serverApi.use('GET:/kqcs/system/bizTemplate/list'),
  paramGroups: [formData, pagination.value.params],
})

onMounted(() => {
  isFirst.value = true
})

onActivated(() => {
    if (isFirst.value || route.meta.isBack ) return
     // 参数清空 重新请求数据
    form.templateName = ''
    pagination.value.params.pageNum = 1
    change(JSON.parse(JSON.stringify(form))) 
})

onDeactivated(() => {
  isFirst.value = false
})

</script>

3、给组件有条件添加keep-alive标签

  <router-view v-slot="{ Component }">
    <keep-alive :include="includeList">
      <component :is="Component" :key="route.path"></component>
    </keep-alive>
  </router-view>
export default defineComponent({
  setup() {
    const router = useRouter()
    const includeList = computed(
      () =>
        router
          .getRoutes()
          .filter((i) => i.meta.keepAlive)
          .map((i) => i.name) as string[]
    )

    return { includeList, route }
  },
})
</script>

includeList中的name会根据组件的name进行匹配, 所以组件想要有条件被KeepAlive缓存,就必须显式生命一个name选项。

Tip:在 3.2.34 或以上的版本中,使用 <script setup 语法糖的单文件组件会自动根据文件名生成对应的 name 选项,无需再手动声明。

以上情况只考虑到查看返回的场景,但在项目中新增、编辑、查看用的同一个页面,所以需根据用户的具体操作做不同处理,从详情页返回有以下三种情况:

1、查看:【详情页】返回【列表页】需缓存数据,不做任何操作;

2、编辑:【详情页】返回【列表页】需缓存数据,重新请求接口;

3、新增:【详情页】返回【列表页】不需要缓存数据,并需要置空查询条件和分页重新请求接口。

在详情页操作时给列表页meta添加操作标识

// views/reviewRecordDetail.vue 详情页

// 新增
async function createTemplateInfo(params) {
  await serverApi.use('POST:/kqcs/system/bizTemplate/bizTemplateAdd')(params)
  ElMessage.success('操作成功')
  router.push('/review-template-mgt')
  route.meta.action = ActionEnum.ADD
}
//编辑
async function editTemplateInfo(params) {
  await serverApi.use('POST:/kqcs/system/bizTemplate/bizTemplateEdit')(params)
  ElMessage.success('保存成功')
  router.push('/review-template-mgt')
  route.meta.action = ActionEnum.EDIT
}

列表页获取route meta中的操作标识处理数据

// views/reviewRecordInfo.vue 列表页

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  beforeRouteEnter(to, from, next) {
    if (from.path == '/review-template-detail') {
      to.meta.isBack = true
      to.meta.action = from.meta.action
    } else {
      to.meta.isBack = false
    }
    next()
  },
})
</script>

  // isFirst为了记录是否是初次进入页面 避免初始化页面调用两次bizTemplate/list接口
  const isFirst = ref(false)

  const [form, change] = useListParam(formData)
    // 此处是自己封装的useDataList, 进入页面则会请求接口
  const { listData, refreshData, selection } = useDataList({
    listApi: serverApi.use('GET:/kqcs/system/bizTemplate/list'),
    paramGroups: [form, pagination.value.params],
  })
  
  onMounted(() => {
    isFirst.value = true
  })

  onActivated(() => {
    if (isFirst.value) return
    // 不是从详情页返回,或者新增成功,则清空数据重新请求
    if (!route.meta.isBack || route.meta.action === ActionEnum.ADD) {
      formData.templateName = ''
      pagination.value.params.pageNum = 1
      change(JSON.parse(JSON.stringify(formData)))
    }
    // 编辑成功后,保留查询条件、分页参数,重新请求列表
    if (route.meta.action === ActionEnum.EDIT) {
      change(JSON.parse(JSON.stringify(formData)))
    }
  })

  onDeactivated(() => {
    isFirst.value = false
  })