背景:
在公式做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>
写完能跑起来了,就放心了。。。这都是什么鬼啊