【Fantastic-admin 技术揭秘】页面组件刷新

《Fantastic-admin 技术揭秘》系列将带你了解 Fantastic-admin 这款框架各种功能的设计与实现。通过了解这些技术细节,你不光可以更轻松地使用 Fantastic-admin 这款框架,也可以在其他项目中使用这些技术。

你可以点击 这里 查看本系列的所有文章,也欢迎你在评论区留言告诉我你感兴趣的内容,或许下一篇文章就会带你揭秘其中的奥秘。

需求分析

页面刷新是很常见的一种用户行为,比如一些表单页面,用户填写了一半数据,这时候打算重新填写,就会通过刷新页面恢复到初始状态。

但直接刷新浏览器会触发整个应用的重新加载,这显然不是我们希望看到的,最好是只刷新当前页面对应的组件。

实现方案

既然是页面组件刷新,那就可以确定下几种方案:

方案一

因为后台框架是嵌套路由的结构,所以可以在共用的父组件里,通过 v-if 来重新渲染 RouterView 组件,达到刷新当前页面的效果。

vue 复制代码
<script setup lang="ts">
import { usePageStore } from '@/store/modules/page';

const { isRefresh } = usePageStore();
</script>

<template>
  <RouterView v-slot="{ Component, route }">
    <KeepAlive :include="keepAliveStore.list">
      <component v-if="!isRefresh" :is="Component" :key="route.fullPath" />
    </KeepAlive>
  </RouterView>
</template>
ts 复制代码
// store/modules/page.ts
export const usePageStore = defineStore('page', () => {
  const isRefresh = ref(false);

  function setRefresh() {
    isRefresh.value = true;

    nextTick(() => {
      isRefresh.value = false;
    });
  }

  return { isRefresh, setRefresh };
});

把是否刷新页面这个状态交给 store 来管理,这样就可以在需要刷新页面的时候,调用 setRefresh 方法,然后页面就会重新渲染。

但是,这个方案有个弊端,因为 RouterView 组件会搭配 KeepAlive 组件一起使用,所以重新渲染 RouterView 组件,会影响到 KeepAlive 组件的缓存效果,这显然不是我们希望看到的。

方案二

既然方案一的通过 v-if 来重新渲染组件的结果不符合预期,那就换一种思路,通过跳转到一个空白页面,再立马跳转回来,也能达到刷新当前页面的效果。

我们需要准备一个 reload 页面,并写进路由配置中:

vue 复制代码
<script setup lang="ts">
const router = useRouter()

onMounted(() => {
  router.go(-1)
})
</script>

<template>
  <div />
</template>
ts 复制代码
// 注意:reload 页面也必须是嵌套路由的结构,确保它和其他业务页面是共用同一个父组件的,这样才能保证在跳转到 reload 页面时,keep-alive 组件的缓存效果不会受到影响
{
  path: '/',
  component: () => import('@/layouts/index.vue'),
  children: [
    {
      path: 'reload',
      name: 'reload',
      component: () => import('@/views/reload.vue'),
      meta: {
        title: '刷新页面',
      },
    },
  ],
}

还有最后一步,如果当前路由页面是开启页面缓存的,那么在跳转到 reload 页面时,需要手动删除下当前页面在 keep-alive 中的缓存。

以上篇《精细化控制页面缓存》文章为例,需要在 router.afterEach 中判断进入的是否为 reload 页面,如果是,则删除当前页面在 keep-alive 中的缓存。

ts 复制代码
// 这段代码如果看不明白,可以先阅读上篇文章
router.afterEach((to, from) => {
  const keepAliveStore = useKeepAliveStore()
  if (to.fullPath !== from.fullPath) {
    if (to.meta.cache) {
      const componentName = to.matched.at(-1)?.components?.default.name
      if (componentName) {
        keepAliveStore.add(componentName)
      }
      else {
        console.warn('该页面组件未设置组件名,会导致缓存失效,请检查')
      }
    }
    if (from.meta.cache) {
      const componentName = from.matched.at(-1)?.components?.default.name
      if (componentName) {
        switch (typeof from.meta.cache) {
          case 'string':
            if (from.meta.cache !== to.name) {
              keepAliveStore.remove(componentName)
            }
            break
          case 'object':
            if (!from.meta.cache.includes(to.name as string)) {
              keepAliveStore.remove(componentName)
            }
            break
        }
        if (from.meta.noCache) {
          switch (typeof from.meta.noCache) {
            case 'string':
              if (from.meta.noCache === to.name) {
                keepAliveStore.remove(componentName)
              }
              break
            case 'object':
              if (from.meta.noCache.includes(to.name as string)) {
                keepAliveStore.remove(componentName)
              }
              break
          }
        }
        // ↓↓↓ 在这里进行处理 ↓↓↓
        // 如果进入的是 reload 页面,则将离开页面的缓存清空
        if (to.name === 'reload') {
          keepAliveStore.remove(componentName)
        }
      }
    }
  }
})

这会,已经能基本满足页面刷新的需求了。

但这个方案也并非完美,因为毕竟是跳转到一个空白页面再跳回来,即便关闭了页面切换动画,在视觉上还是会看到页面闪烁了一下。

但话又说回来,这个闪烁的效果,或许也能作为用户反馈的一种形式,让用户知道页面刷新了。

相关推荐
恋猫de小郭36 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端