Vue2的router-view,keep-alive和el-tabs结合做标签页切换
Vue2的router-view,keep-alive和el-tabs结合做标签页切换,并实现iframe组件的缓存
·
注意要点:
1.每个页面组件需要置顶的name属性,与cachedViews数组里的名称一致
2.如果是多级页面缓存,一定要加上他父组件的name,比如我的是layoutEmpty
3.在main.vue和empty.vue里的router-view都需要用keep-alive包装
4.在router/index.js里每个路由都要在meta里面增加keepAlive来标识是否需要缓存
5.我这有iframe组件,所以也进行了标识,iframe缓存用的是component组件的is来实现的
这是empty.vue
<template>
<div>
<keep-alive :include="cachedViews">
<router-view v-if="$route.meta.keepAlive&&!$route.meta.isIframe" :key="key"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive&&!$route.meta.isIframe" :key="key"/>
</div>
</template>
<script>
export default {
name: 'layoutEmpty',
computed: {
key() {
return this.$route.path
},
cachedViews() {
return this.$store.state.cachedViews
}
}
}
</script>
这是AppMain.vue,backTop是自己写的返回顶部组件,可以不用加
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in" :duration="500">
<back-top>
<keep-alive :include="cachedViews">
<router-view v-if="$route.meta.keepAlive&&!$route.meta.isIfram" :key="key"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive&&!$route.meta.isIfram" :key="key"/>
<div v-for="item in hasOpenIframeComponentsArr" :key="item.name" >
<component
v-show="$route.name === item.name&&item.hasOpen"
:key="item.name"
:is="item.name"
></component>
</div>
</back-top>
</transition>
</section>
</template>
<script>
import BackTop from '@/components/BackTop'
import Vue from 'vue'
export default {
name: 'AppMain',
components: {
BackTop,
},
computed: {
key() {
return this.$route.path
},
cachedViews() {
return this.$store.getters.cachedViews
},
// Implement lazy loading to render only iframe pages that have been opened (hasOpen:true)
hasOpenIframeComponentsArr() {
return this.openedIframeComponentsArr;
},
},
data() {
return {
iframeComponentsArr: [], // Pages with iframe
openedIframeComponentsArr: []
}
},
methods: {
// 给当前iframe组件增加hasOpen
isOpenIframePage() {
const target = this.iframeComponentsArr.find(item => {
return item.name === this.$route.name
});
if (target && !target.hasOpen) {
target.hasOpen = true;
this.openedIframeComponentsArr.push(target)
}
},
// 获取iframe组件数组
getIframeComponentsArr() {
const router = this.$router;
const routes = router.options.routes[1].children;
let iframeArr = []
for (let item of routes){
if (item.children){
iframeArr.push(...item.children.filter(item => item.iframeComponent))
}
}
return iframeArr.map((item) => {
const name = item.name || item.path.replace('/', '');
return {
name: name,
path: item.path,
hasOpen: false, // Whether it has been opened, default false
component: item.iframeComponent // Reference to Component Files
};
});
}
},
watch: {
// 当route切换的时候执行
$route() {
// Determine whether the current routing is an iframe page
this.isOpenIframePage();
}
},
created() {
// Setting the array object for the iframe page
const iframeComponentsArr = this.getIframeComponentsArr();
iframeComponentsArr.forEach((item) => {
Vue.component(item.name, item.component);
});
this.iframeComponentsArr = iframeComponentsArr;
// Determine whether the current routing is an iframe page
this.isOpenIframePage();
},
}
</script>
<style lang='scss' scoped>
.app-main {
// min-height: calc(100vh - 50px);
height: 100%;
width: 100%;
position: relative;
overflow: auto;
}
.fixed-header+.app-main {
padding-top: 84px;
}
</style>
<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
.fixed-header {
padding-right: 15px;
}
}
</style>
在store/index.js里需要初始化定义一下
const state = sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : {
visitedViews: [],
cachedViews: ["layoutEmpty"],
activeIndex: ''
}
这是store/mutations.js
// 添加tab
const add_visited_view = (state, view) => {
var tab_data = {path: view.path, title: view.meta.title, closable: view.meta.closable, name: view.name}
if (state.visitedViews.some(v => v.path === view.path)) return
state.visitedViews.push(tab_data);
}
// 添加缓存的页面
const add_cached_view = (state, view) => {
if (state.cachedViews.includes(view.name)) return
if (view.meta.keepAlive) {
state.cachedViews.push(view.name);
}
}
// 删除tabs里的tab
const delete_visited_view = (state, view) => {
for (const [i, v] of state.visitedViews.entries()) {
if (v.path === view.path) {
state.visitedViews.splice(i, 1)
break
}
}
}
// 删除缓存的页面
const delete_cached_view = (state, view) => {
const index = state.cachedViews.indexOf(view.name)
index > -1 && state.cachedViews.splice(index, 1)
}
export default {
// 添加tabs
add_view (state, view) {
add_visited_view(state, view);
add_cached_view (state, view);
},
// 删除tabs
delete_view (state, view) {
delete_visited_view(state, view);
delete_cached_view(state, view);
},
// 设置当前激活的tab
set_active_tab (state, index) {
state.activeIndex = index;
}
}
这是store/getter.js
const getters = {
activeIndex: state => state.activeIndex,
visitedViews: state => state.visitedViews,
cachedViews: state => state.cachedViews
}
export default getters
这是tags.vue
<template>
<div>
<el-row>
<el-col :span="24">
<el-tabs v-model="activeIndex" type="card" @tab-remove="removeTab" @tab-click="tabClick">
<el-tab-pane
v-for="item in visitedViews"
:key="item.title"
:label="item.title"
:name="item.path"
:closable="item.closable"
>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
</div>
</template>
<script>
import { generateTitle } from '@/utils/i18n'
export default {
name: 'TabsNav',
props: { },
data () {
return {
}
},
created () {
this.$nextTick(()=> {
this.activeIndex = this.$route.path;
});
},
watch: {
$route:{
handler(to, from){
this.addTabs();
this.moveToCurrentTag();
},
deep: true
}
},
mounted () {
// 刷新时以当前路由做为tab加入tabs
// 当前路由不是首页时,添加首页以及另一页到store里,并设置激活状态
// 当前路由是首页时,添加首页到store,并设置激活状态
this.initTabs()
this.addTabs()
},
computed: {
visitedViews () {
return this.$store.getters.visitedViews
},
activeIndex: {
get () {
return this.$store.getters.activeIndex
},
set (val) {
this.$store.commit('set_active_tab', val)
}
}
},
methods: {
generateTitle,
//删除tab
removeTab(target) {
if ( target == '/' || target == '/home' ){
return
}
this.$store.commit('delete_view', this.$route)
if (this.activeIndex === target) {
// 设置当前激活的路由
if (this.visitedViews && this.visitedViews.length >= 1) {
this.$store.commit('set_active_tab', this.visitedViews[this.visitedViews.length - 1].path)
this.$router.push({path: this.activeIndex})
}
}
},
//tab点击
tabClick(tab){
this.$router.push({path: tab.name})
},
// 添加tab
addTabs() {
const { name } = this.$route
if (name) {
this.$route.meta.title = this.generateTitle(this.$route.meta.title)
this.$route.meta.closable = true
this.$store.commit('add_view', this.$route)
}
return false
},
// 切换活动页
moveToCurrentTag() {
this.$store.commit('set_active_tab', this.$route.path)
},
// 初始化tabs
initTabs(){
var flag = this.visitedViews.some(item=>{
if(item.name == 'Home'){
return true
}
})
if (!flag){
const data = {
path: '/home',
name: 'Home',
meta: {
title: this.generateTitle('home'),
closable: false,
keepAlive: false
}
}
this.$store.commit('add_view', data)
}
this.$store.commit('set_active_tab', this.$route.path)
}
},
}
</script>
最终使用的是在index.vue里
<el-container>
<el-header>
<div>
<tags />
</div>
</el-header>
<el-main class="main-container" style="background: white;">
<app-main />
</el-main>
</el-container>
参考资料
keep alive (no refresh) for iframe in Vue
vue3使用 keep-alive对iframe进行缓存_叫我多多酱的博客-CSDN博客_vue 缓存iframe
vue移动端项目缓存问题实践_Android开发者小P的博客-CSDN博客
https://www.jb51.net/article/205539.htm
Vue keep-alive 多级页面不缓存问题_始于颜值 陷于才华 忠于人品的博客-CSDN博客_keep-alive 不缓存
更多推荐
已为社区贡献3条内容
所有评论(0)