vue多标签页效果¶
1. 业务场景¶
vue框架实现的后台管理系统中添加多标签页;记录用户已经打开过的页面,方便页面的快速切换;
效果如图:
2. 任务¶
- 当用户点击左侧菜单项,切换页面时,右侧内容顶部出现标签页;
- 重复出现的标签页自动过滤;
- 点击标签页能快速跳转到相应页面;
- 可以关闭指定标签页;
- 刷新网页,标签页状态保持不变;
3. 实现任务¶
-
vuex定义路由数组记录浏览过的路由
state: { visitedviews: [],//存放所有浏览过的且不重复的路由数据 }
-
watch观察路由变化
watch: { $route() { this.addViewTags(); } }
-
切换菜单,路由变化时将路由对象添加到vuex定义的路由数组中
//路由改变时执行的方法 addViewTags() { if (this.$route.name) { const route = this.$route; this.$store.dispatch("addVisitedViews", route); } }
-
计算属性监听store存储标签数据变化
computed: { visitedViews() { //store中取值,可以定义getter取值 this.$store.getters.visitedviews //return this.$store.state.tagsview.visitedviews; return this.$store.getters.visitedviews; } },
-
关闭标签时删除vuex路由数组中路由对象
//如果关闭的是当前打开的路由需要将路由改为数组最后一次push进去的路由 delSelectTag(route) { this.$store.dispatch("delVisitedViews", route).then(views => { //只有在关闭当前打开的标签页才会有影响 if (this.isActive(route)) { let lastView = views.slice(-1)[0]; //选取路由数组中的最后一位 if (lastView) { this.$router.push(lastView); } else { this.$router.replace("/"); } } }); }
-
vuex存储store具体实现:
store/modules/下新建tagsview.js
const tagsview = {
state: {
visitedviews: [],//存放所有浏览过的且不重复的路由数据
},
mutations: {
ADD_VISITED_VIEWS: (state, view) => {//打开新页签--添加路由数据的方法
if (state.visitedviews.some(v => v.path == view.path)) return;
console.log('view ',view);
state.visitedviews.push({
name: view.name,
path: view.path,
title: view.meta.title || 'no-title'
})
},
DEL_VISITED_VIEWS: (state, view) => {//关闭页签--删除路由数据的方法
for (let [i, v] of state.visitedviews.entries()) {
if (v.path == view.path) {
state.visitedviews.splice(i, 1)
break
}
}
},
},
actions: {
//调用这里去触发mutations,如何调用?在组件内使用this.$store.dispatch('action中对应名字', 参数)
addVisitedViews({ commit }, view) {
commit('ADD_VISITED_VIEWS', view)
},
//删除数组存放的路由之后,需要再去刷新路由,这是一个异步的过程,需要有回掉函数,所以使用并返回promise对象,也可以让组件在调用的时候接着使用.then的方法
delVisitedViews({ commit,state }, view) {
//commit('DEL_VISITED_VIEWS',view)
return new Promise((resolve) => {//resolve方法:成功回调的方法
commit('DEL_VISITED_VIEWS', view);
resolve([...state.visitedviews]);
})
}
}
}
export default tagsview
-
封装标签页组件TagsView
-
标签项由 router-link 组件实现
<router-link :to="path">添加客户</router-link>
-
TagsView组件具体实现
<template> <div class="tags-view-container"> <router-link v-for="tag in Array.from(visitedViews)" :to="tag.path" :key="tag.path" class="tags-view-item" :class="isActive(tag)?'active':''" > <span class="el-icon-switch-button" v-show="isActive(tag)"></span> {{tag.title}} <span class="el-icon-close" @click.prevent.stop="delSelectTag(tag)"></span> </router-link> </div> </template> <script> export default { name: "TagsView", data() { return { active: "active" }; }, computed: { visitedViews() { //store中取值,可以定义getter取值 this.$store.getters.visitedviews return this.$store.state.tagsview.visitedviews; //return this.$store.getters.visitedviews; } }, methods: { isActive(route) { return route.path == this.$route.path; }, addViewTags() { //路由改变时执行的方法 if (this.$route.name && this.$route.name != "index") { const route = this.$route; this.$store.dispatch("addVisitedViews", route); } }, delSelectTag(route) { //先提交删除数据的方法,数组删除出掉数据后,如果关闭的是当前打开的路由需要将路由改为数组最后一次push进去的路由 this.$store.dispatch("delVisitedViews", route).then(views => { if (this.isActive(route)) { //只有在关闭当前打开的标签页才会有影响 let lastView = views.slice(-1)[0]; //选取路由数组中的最后一位 if (lastView) { this.$router.push(lastView); } else { this.$router.replace("/index"); } } }); } }, watch: { $route() { this.addViewTags(); } } }; </script> <style lang="css" scoped> .tags-view-container { margin: 10px 0; padding: 10px 15px; box-shadow: 0 4px 8px 0 rgba(7, 17, 27, 0.1); background-color: #fff; } .tags-view-item { margin-right: 10px; border: 1px solid rgb(224, 219, 219); background: rgb(243, 247, 243); padding: 3px 8px; display: inline-block; font-size: 14px; color: rgb(44, 43, 44); } .tags-view-item:hover { background: #40bb84; color: white; } .active { margin-right: 10px; border: 1px solid rgb(224, 219, 219); background: #40bb84; padding: 3px 8px; display: inline-block; color: white; } </style>
-
cookie存储tags标签数据
/** * 持久存储封装 cookie * */ import Cookies from "js-cookie"; const Tags_KEY = 'tags-key'; /** * 保存存tags对象 * @param {*} tags */ const saveTags = (tags) => { Cookies.set(Tags_KEY, tags) } /** * 获取tags状态对象 */ const getTags = () => { const tagsStr = Cookies.get(Tags_KEY); if (tagsStr) { return JSON.parse(tagsStr); } else { return null; } } /** * 移除tags对象 */ const removeTags = () => { Cookies.remove(Tags_KEY); } export { saveTags, getTags, removeTags }
4. 得到的结果¶
- watch侦听器的应用
- 路由对象$route使用
- 组件封装
- vuex使用
- cookie存储标签页