最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue-element-admin 中三级路由缓存问题

    正文概述 掘金(iwhao_top)   2021-03-10   1411

    写法问题,实现三级嵌套,二级路由 需要继承空模板


    import Empty from '@/layout/empty.vue'
    
    {
        name: 'One',
        path: '/one',
        component: 'Layout',
        alwaysShow: true,
        meta: { title: '一级', icon: 'tool' },
        children: [
          {
            name: 'Empty',
            path: '/one/two',
            component: Empty,
            alwaysShow: true,
            meta: { title: '二级', icon: 'tool' },
            children: [
              {
                name: 'Three',
                path: '/one/two/three',
                component: () =>import('@/views/three/index'),
                meta: { title: '三级', icon: 'build' }
              }
            ]
          }
        ]
    }
    

    empty.vue 如果想要三级页面缓存的话一定要加 keep-alive 不然缓存不上,不需要缓存就不用加

    <template>
      <keep-alive :include="cachedViews">
        <router-view :key="key" />
      </keep-alive>
    </template>
    <script>
    export default {
      name: 'Empty',
      computed: {
        cachedViews() {
          return this.$store.state.tagsView.cachedViews
        },
        key() {
          return this.$route.path
        }
      }
    }
    </script>
    

    三级路由 不缓存 的问题 原因


    keep-alive的组件依赖cachedViews,cachedViews是store中的一个状态, cachedViews的逻辑在src/layout/TagView,当路由变更时就会调用addViewTags,addViewTag会根据匹配的路由name属性进行缓存。而用到三级路由的时候,拿到的name只能是第三级路由的name,二级路由继承的模板的名字会丢失,keep-alive就不会进行缓存。

    解决办法

    在 tagsView.js 中 缓存中提前加上二级菜单得 name

    const state = {
      visitedViews: [],
      cachedViews: ['Empty']
    }
    

    上述方法可以 解决缓存问题,但随后出现的问题是,关闭三级页面后 虚拟dom 还是存在,造成不好的后果就是,一是内存占用过大 浪费资源,再就是 当你切换路由和在tab标题签上右键刷新时 会调用 那些没 清除的缓存页面createdmounted

    当时博主也很纳闷,明明只剩下了 首页,再打开新页面的时候,NetWork 里有许多之前已经关闭了的 页面的 接口请求

    借助vueDevTools 后,真相水落石出

    vue-element-admin 中三级路由缓存问题

    每次打开三级页面后都会多一个 Emptty dom,想过后才知道,\src\layout\components\AppMain.vueempty.vue 两个模板都加了 keep-alive, 而所有的三级页面的父级模板都是上文中的Empty,这就导致了 只要打开三级页面 就会出现一个 Emptty,并且因为三级路由缓存的需要,并不能准确的知道何时需要清除二级模板的缓存

    所以 博主目前 的 解决方案是 将三级路由 全部提升至 二级路由 变成以下格式,对于路径展示 还是三级路由的效果

     {
        name: 'One',
        path: '/one',
        component: 'Layout',
        alwaysShow: true,
        meta: { title: '一级', icon: 'tool' },
        children: [
            {
                name: 'Three',
                path: '/one/two/three',
                component: () =>import('@/views/three/index'),
                meta: { title: '/二级/三级', icon: 'build' }
            }
        ]
    }
    

    对于 路由设置是从接口获取数据的 就需要在store 中 permission.js 中请求路由时 自己加工处理下了

       // 遍历后台传来的路由字符串,转换为组件对象
    function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
      return JSON.parse(JSON.stringify(asyncRouterMap)).filter(route => {
        // 处理 vue-router所需要路由 Empty(继承Empty模板的层)的children全部提到上一层
        if (type && route.children) {
          route.children = filterChildren(route.children)
        }
        // 拼装路由
        if (lastRouter && route.path.indexOf('http') === -1) {
          route.path = lastRouter.path + '/' + route.path
        }
    
        if (route.component) {
          // Layout组件特殊处理
          if (route.component === 'Layout') {
            route.component = Layout
          } else if (route.component === 'Empty') {
            route.component = Empty
          } else {
            route.component = loadView(route.component) // route.component是一个字符串 这里是字符串转组件对象
          }
        }
        // 如果有子集 递归调用
        if (route.children != null && route.children && route.children.length) {
          route.children = filterAsyncRouter(route.children, route, type)
        }
        return true
      })
    }
    //
    function filterChildren(childrenMap, lastRouter = false) {
      var children = []
      JSON.parse(JSON.stringify(childrenMap)).forEach((el, index) => {
        if (el.children && el.children.length) {
          if (el.component === 'Empty') {
            el.children.forEach(c => {
              c.path = el.path + '/' + c.path
              if (c.children && c.children.length) {
                children = children.concat(filterChildren(c.children, c))
                return
              }
              children.push(c)
            })
            childrenMap.splice(index, 1)
            return
          }
        }
        if (lastRouter) {
          el.path = lastRouter.path + '/' + el.path
        }
        children = children.concat(el)
      })
      return children
    }
    export const loadView = view => {
      // 路由懒加载
      return () => import(`@/views/${view}`) // 异步动态加载
    }
    

    注意:原文作者中也有提到,由于目前 keep-aliverouter-view 是强耦合的,而且查看文档和源码不难发现 keep-alive 的 include 默认是优先匹配组件的 name ,所以在编写路由 router 和路由对应的 view component 的时候一定要确保 两者的 name 是完全一致的。(切记 name 命名时候尽量保证唯一性 切记不要和某些组件的命名重复了,不然会递归引用最后内存溢出等问题)

    原文-文档

    欢迎关注我的公众号:前端技术战(注意,是战斗呦)

    如果可以

    vue-element-admin 中三级路由缓存问题

    我的博客

    我的掘金

    我的简书

    Laravel China


    起源地下载网 » vue-element-admin 中三级路由缓存问题

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元