Vue笔记一使用keep-alive缓存三级路由页面

1,798 阅读3分钟
业务需求

在最近的一个vue项目开发过程中,遇到这么一个业务需求:用户需要能够打开多个路由页面,并且在切换打开的路由页面时保留原来页面的数据。

keep-alive

熟悉vue的同学一定知道,在router-view外层加上个keep-alive就能够缓存页面数据。

<keep-alive :include="includeList" :exclude="tabExclude">
    <router-view></router-view>
</keep-alive>

把需要缓存数据的路由添加到数组includeList中,keep-alive就能够缓存里面路由页面上的数据。

问题

然而,测试的时候发现了一个问题:keep-alive只能缓存二级路由页面的数据,三级以及三级以上的路由页面缓存不了,怎么办呢?

百度

网上找到了一个简单的方法:在路由文件router/index.js中处理后端返回给我们前端的路由时,先把路由扁平化处理,即将有三级路由的二级路由找出来去掉。

function handleKeepAlive(to) {
    if (to.matched && to.matched.length > 2) {
        for (let i = 0; i < to.matched.length; i++) {
            const element = to.matched[i]
            if (secAndThirdList.indexOf(element.components.default.name) > -1) {
                to.matched.splice(i, 1)
                handleKeepAlive(to)
            }
        }
    }

把这个方法置于router.addRoute(r)之后,再一测,诶,好像还真的可以哦。哈哈,你高兴得太早了。(PS:secAndThirdList是自己从所有路由里面过滤出来的含有三级路由的二级路由的路由id集合。)

这样解决表面上看起来的确是能够把三级路由页面的数据缓存起来了,但实际上却隐藏着一个缺陷,就是系统首次登录进来时切换三级路由页面依旧不能缓存页面数据,退出再次登录后才可以(这样都能被测试发现,厉害),而且切换到三级路由页面时会再次请求该路由的接口,造成性能浪费。

再次百度

好的,面向百度开发。网上找到了很多方法,但是看代码感觉好复杂,跟我项目中的代码也有很多不同之处。我是个懒人,那有没有简单一点的方法呢?找了好久,终于在网上找到了另外一种说法(思路):keep-alive之所以没有缓存到三级路由,是因为我们没有把二级路由也加入到前面提到的includeList中。

嗯?从存到session里面看includeList,果然没有。那不妨先试一试。不过这个项目中多路由页面都是从includeList里面取,而那些“特殊”的二级路由是没有对应的页面的,所以我们需要在取值过程中把这些二级路由剔除出去。

// oldMenuList是接口返回的所有路由数组对象
let oldMenuList = sessionStorage.getItem('oldMenuList') ? JSON.parse(sessionStorage.getItem('oldMenuList')) : []
oldMenuList.forEach(item => {
    item.path = item.menuUrl
    item.name = item.menuId
    item.meta = {
        icon: item.imageUrl,
        title: item.menuName,
    }
    item.fullPath = item.menuUrl
    item.query = {}
    item.params = {}
})
if (to.matched.length > 2) {
    let matchedNameList = to.matched.map((item, index) => {
        if (index > 0) {
            return item.name
        }
    })
    for (let i = 0; i < oldMenuList.length; i++) {
        // 给特殊的二级路由加入标识,便于后面过滤剔除
        if (matchedNameList.indexOf(oldMenuList[i]) > -1) {
            if (secAndThirdList.indexOf(oldMenuList[i]) > -1) {
                oldMenuList[i].filterTab = true
            }
            // 最后才加入到tabList(includeList取自vuex里面的tabList)
            store.commit('OPEN_TAB', oldMenuList[i])
        }
    }
} else {
    store.commit('OPEN_TAB', to)
}

然后在多路由切换组件ALiveTab.vue中修改一下取值方法

<script>
import { mapGetters } from 'vuex'

export default {
    data() {
        return {
            filterTabList: []
        }
    },
    computed: {
        ...mapGetters({
            tabList: 'getTabList'
        })
    },
    methods: {},
    mounted() {
        this.filterTabList = this.tabList.filter(t => !t.filterTab)
    },
    watch: {
        tabLsit: {
            handler(val) {
                if (val) {
                    this.filterTabList = this.tabList.filter(t => !t.filterTab)
                }
            }
        }
    }
}

最后完成测试一下,不管是首次登录还是退出再登录,刷新页面还是切换角色,二级路由还是三级路由,都可以切换缓存页面数据了, 呼~终于完成了。代码拙劣,欢迎各路大神指正。