背景:
在公式做ms管理系统。然后老大看事情做差不错了,想要优化一下用户体验。要我在每次用户切换页面后创建一个类似浏览器多页面tag的导航。这样用户在使用时方便做数据比较。
最后长这样
分析:
这个放在以前那就是多开一个页面的事儿,让浏览器帮我们保存数据和结构。放到vue里面,因为我们的结构是根据数据决定的,那就是保存一下数据的概念。保存数据的方式瞬间想到sessionstorage、localstorage,但是显然这两个是浏览器级别的,我们是有权限控制的所以pass掉。那就只能放在我们页面的数据里面了。
因为是全局的,你需要在所有页面都可以读取、删除。那就放在vuex这个状态机里面。
然后状态机里面你需要做几件事:
1、添加这个tag(你可能需要判断是否数量会太多,太多的话会影响性能)
2、更新这个tag(更新根据数组的键,就可以了)
3、销毁这个tag
数据
export default {
state: {
tags: [],//访问过的页面集合
deepCopy: function(initalObject, finalObject) {
var finalObject = finalObject || {}
for (var key in initalObject) {
var tempProperty = initalObject[key]
if (tempProperty === initalObject) {
continue //当自身属性引用自己的时候,跳过执行,不拷贝,避免相互引用导致内存溢出的情况
}
if (typeof initalObject[key] === "object" && initalObject[key] !== null) {
finalObject[key] = (initalObject[key].constructor === Array) ? [] : {} //区分构造函数
this.deepCopy(initalObject[key], finalObject[key]) //调用自身函数方法
} else {
finalObject[key] = initalObject[key]
}
}
return finalObject
}
},
getters: {
tags(state) {
return state.tags;
}
},
mutations: {
//将tag放进tags
addTags(state, tag) {
let index = state.tags.length;
if (index > 8) {
state.tags.splice(index > 0 ? index - 1 : 0, 1, state.deepCopy(tag));
} else {
state.tags.splice(index > 0 ? index : 0, 0, state.deepCopy(tag));
}
},
/*
*tag.index和state.tags[tag.index]判断key值是否正确以及是否存在数据
*state.tags[tag.index].name == tag.name 确定修改的路径是否一致,防止删除时修改
*/
updateTags(state, tag) {
if (tag.index !== null && state.tags[tag.index] && state.tags[tag.index].name == tag.name) {
let data = {
name: state.tags[tag.index].name,
data: state.deepCopy(tag.data)
}
state.tags.splice(tag.index, 1, data);
}
},
delTags(state, index) {
state.tags.splice(index, 1)
},
//从tag进入时,由缓存初始化数据
cacheDataInit(state, { that, datashow }) {
let datas = that.$data;
Object.keys(datas).forEach((val) => {
that[val] = datashow[val]
})
}
},
actions: {
/*
*在模块复用的时候调用的时候更新数据
*that 页面this参数
*to route中的to参数
*/
beforeRouteUpdate({ commit, state }, { that, to }) {
let status = that.$route.query.status;
if (status === 'cache') {
let index = that.$route.query.key;//该tag在tags数组中的键
let data = {
index,
data: that.$data,
name: that.$route.path
}
commit('updateTags', data);
}
},
/*
*在路由跳转之前更新数据
*that 页面this参数
*/
beforeRouteLeave({ commit, state }, that) {
if (that.$route.query.status === 'cache') {
let index = that.$route.query.key;
let data = {
index,//所处的键,方便定位到tag
data: that.$data,//页面数据
name: that.$route.path//路由名
}
commit('updateTags', data)
} else {
let data = {
name: that.$route.path,
data: that.$data
}
commit('addTags', data)
}
},
/*
*从vuex更新页面的数据
*that 页面this
*/
cacheDataInit({ commit, state }, that) {
let key = that.$route.query.key;
let datashow = state.tags[key].data;
commit('cacheDataInit', { that, datashow })
}
}
}
调用
调用刚开始想在全局直接调用,这样就不用每一个单独去写了啊。然后发现route的全局守卫里面,beforeEach和afterEach这两个内部都没办法使用this。我们内部是一定会调用this来赋值的。所以只能使用组件内守护。beforeRouteEnter(不能读取this排除)、
beforeRouteLeave、beforeRouteUpdate。
beforeRouteLeave:在路由离开之前触发。那就可以在这个时候添加我们的tag了。
beforeRouteUpdate:在路由更新时触发。这个时候是不是就可以读取我们的缓存呢??完美
created() {
let status = this.$route.query.status;//根据status状态来确认是正常的导航还是缓存导航
if (status === 'cache') {
this.cacheDataInit(this)
} else {
this.getData();//正常获取数据
}
},
beforeRouteLeave(to, from, next) {//离开之前调用添加tag方法
this.beforeRouteLeave(this)
next()
},
beforeRouteUpdate(to, from, next) {//路由更新时传入进入和离开路由进行判断
if (!this.$route.query.status && to.query) {
this.$route.query.key = to.query.key;
this.cacheDataInit(this)
} else {
this.beforeRouteUpdate({ that: this, to })
}
next();
}
tag导航
<div id="scrollNav" v-if='tags.length'>
<router-link :to="{path:tag.name,query:{status:'cache',key:key}}" v-for='(tag,key) in tags' :key='key' tag="span">
{{_navName(tag.name)}}/*_navName是根据tag.name返回导航中文的方法*/
<i class="el-icon-error" @click.stop="delTags(key)"></i>
</router-link>
</div>
写完能跑起来了,就放心了。。。这都是什么鬼啊