【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)
        }
      }
    }
  }
})

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

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

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

相关推荐
Anlici34 分钟前
跨域解决方案还有优劣!?
前端·面试
苹果电脑的鑫鑫36 分钟前
在使用element-ui时表单的表头在切换页面时第一次进入页面容易是白色字体解决方法
javascript·vue.js·ui
庸俗今天不摸鱼40 分钟前
【万字总结】构建现代Web应用的全方位性能优化体系学习指南(二)
前端·性能优化·webp
潜龙在渊灬1 小时前
杂谈:前端 UI 框架和 UI 组件库的区别
javascript·vue.js·react.js
追寻光1 小时前
Java 绘制图形验证码
java·前端
前端snow1 小时前
爬取数据利用node也行,你知道吗?
前端·javascript·后端
村头一颗草1 小时前
高德爬取瓦片和vue2使用
前端·javascript·vue.js
远山无期1 小时前
vue3+vite项目接入qiankun微前端关键点
前端·vue.js
陈随易1 小时前
告别Node.js:2025年,我为何全面拥抱Bun
前端·后端·程序员
还是鼠鼠1 小时前
Node.js--exports 对象详解:用法、示例与最佳实践
前端·javascript·vscode·node.js·web