Commit 094fd58a authored by 仇晓婷's avatar 仇晓婷

多页签优化

parent 7b811b92
......@@ -9,96 +9,117 @@ import { getAllSiderMenu, includeArray } from '@/libs/system';
// 判定是否需要缓存
const isKeepAlive = data => get(data, 'meta.cache', false);
export const strict=false;
export const state=()=>({
// 可以在多页 tab 模式下显示的页面
pool: [],
// 当前显示的多页面列表
opened: Setting.page.opened,
// 当前页面
current: '',
// 需要缓存的页面 name
keepAlive: []
export const strict = false;
export const state = () => ({
// 可以在多页 tab 模式下显示的页面
pool: [],
// 当前显示的多页面列表
opened: Setting.page.opened,
// 当前页面
current: '',
// 需要缓存的页面 name
keepAlive: []
})
export const actions={
/**
* @description 从持久化数据载入分页列表
*/
openedLoad ({ state, commit, dispatch, rootState }) {
return new Promise(async resolve => {
// store 赋值
const value = await dispatch('admin/db/get', {
dbName: 'sys',
path: 'page.opened',
defaultValue: Setting.page.opened,
user: true
}, { root: true });
// 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签
// 以 fullPath 字段为准
// 如果页面过多的话可能需要优化算法
// valid 有效列表 1, 1, 0, 1 => 有效, 有效, 失效, 有效
const valid = [];
// 处理数据
state.opened = value.map(opened => {
// 忽略首页
if (opened.fullPath === '/index') {
valid.push(1);
return opened;
}
// 尝试在所有的支持多标签页的页面里找到 name 匹配的页面
const find = state.pool.find(item => item.name === opened.name);
// 记录有效或无效信息
valid.push(find ? 1 : 0);
// 返回合并后的数据 新的覆盖旧的
// 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存
return Object.assign({}, opened, find);
})
.filter((opened, index) => valid[index] === 1)
// 对 menu 鉴权过滤
.filter(opened => {
const allSiderMenu = getAllSiderMenu(menuSider);
const find = allSiderMenu.find(item => item.path === opened.fullPath);
export const actions = {
/**
* @description 从持久化数据载入分页列表
*/
openedLoad({ state, commit, dispatch, rootState }) {
return new Promise(async resolve => {
// store 赋值
const value = await dispatch('admin/db/get', {
dbName: 'sys',
path: 'page.opened',
defaultValue: Setting.page.opened,
user: true
}, { root: true });
// 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签
// 以 fullPath 字段为准
// 如果页面过多的话可能需要优化算法
// valid 有效列表 1, 1, 0, 1 => 有效, 有效, 失效, 有效
const valid = [];
// 处理数据
state.opened = value.map(opened => {
// 忽略首页
if (opened.fullPath === '/index') {
valid.push(1);
return opened;
}
// 尝试在所有的支持多标签页的页面里找到 name 匹配的页面
const find = state.pool.find(item => item.name === opened.name);
// 记录有效或无效信息
valid.push(find ? 1 : 0);
// 返回合并后的数据 新的覆盖旧的
// 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存
return Object.assign({}, opened, find);
})
.filter((opened, index) => valid[index] === 1)
// 对 menu 鉴权过滤
.filter(opened => {
const allSiderMenu = getAllSiderMenu(menuSider);
const find = allSiderMenu.find(item => item.path === opened.fullPath);
let state = true;
if (find && find.auth) {
const userInfo = rootState.admin.user.info;
// @权限
const access = userInfo.access;
// 如果用户当前的权限,不是该 menu 对应的 权限,则过滤这个 Tab
if (access && !includeArray(find.auth, access)) state = false;
}
return state;
let state = true;
if (find && find.auth) {
const userInfo = rootState.admin.user.info;
// @权限
const access = userInfo.access;
// 如果用户当前的权限,不是该 menu 对应的 权限,则过滤这个 Tab
if (access && !includeArray(find.auth, access)) state = false;
}
return state;
});
// 根据 opened 数据生成缓存设置
commit('keepAliveRefresh');
// end
resolve();
});
},
/**
* 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened
*/
opened2db ({ state, dispatch }) {
return new Promise(async resolve => {
// 设置数据
dispatch('admin/db/set', {
dbName: 'sys',
path: 'page.opened',
value: state.opened,
user: true
}, { root: true });
// end
resolve();
});
},
/**
* @description 更新页面列表上的某一项
* @param {Object} param { index, params, query, fullPath } 路由信息
*/
openedUpdate ({ state, commit, dispatch }, { index, params, query, fullPath, meta }) {
return new Promise(async resolve => {
// 更新页面列表某一项
// 根据 opened 数据生成缓存设置
commit('keepAliveRefresh');
// end
resolve();
});
},
/**
* 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened
*/
opened2db({ state, dispatch }) {
return new Promise(async resolve => {
// 设置数据
dispatch('admin/db/set', {
dbName: 'sys',
path: 'page.opened',
value: state.opened,
user: true
}, { root: true });
// end
resolve();
});
},
/**
* @description 更新页面列表上的某一项
* @param {Object} param { index, params, query, fullPath } 路由信息
*/
openedUpdate({ state, commit, dispatch }, { index, params, query, fullPath, meta }) {
return new Promise(async resolve => {
// 更新页面列表某一项
let page = state.opened[index];
page.params = params || page.params;
page.query = query || page.query;
page.fullPath = fullPath || page.fullPath;
page.meta = meta || page.meta;
state.opened.splice(index, 1, page);
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 更新页面当前项
* @param {Object} param { params, query, fullPath } 路由信息
*/
currentUpdate({ state, commit, dispatch }, { params, query, fullPath, meta }) {
return new Promise(async resolve => {
setTimeout(async () => {
// 更新当前项
const index = state.opened.findIndex(item => item.fullPath === state.current);
let page = state.opened[index];
page.params = params || page.params;
page.query = query || page.query;
......@@ -109,324 +130,314 @@ export const actions={
await dispatch('opened2db');
// end
resolve();
}, 0);
});
},
/**
* @description 新增一个 tag (打开一个页面)
* @param {Object} param new tag info
*/
add({ state, commit, dispatch }, { tag, params, query, fullPath }) {
return new Promise(async resolve => {
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
let newTag = tag;
newTag.params = params || newTag.params;
newTag.query = query || newTag.query;
newTag.fullPath = fullPath || newTag.fullPath;
// 添加进当前显示的页面数组
state.opened.push(newTag);
// 如果这个页面需要缓存 将其添加到缓存设置
if (isKeepAlive(newTag)) {
commit('keepAlivePush', tag.name);
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 打开一个新的页面
* @param {Object} param 从路由钩子的 to 对象上获取 { name, params, query, fullPath } 路由信息
*/
open({ state, commit, dispatch }, { name, params, query, fullPath }) {
return new Promise(async resolve => {
// 已经打开的页面
let opened = state.opened;
// 判断此页面是否已经打开 并且记录位置
let pageOpenedIndex = 0;
const pageOpened = opened.find((page, index) => {
const same = page.fullPath === fullPath;
pageOpenedIndex = same ? index : pageOpenedIndex;
return same;
});
},
/**
* @description 更新页面当前项
* @param {Object} param { params, query, fullPath } 路由信息
*/
currentUpdate ({ state, commit, dispatch }, { params, query, fullPath, meta }) {
return new Promise(async resolve => {
setTimeout(async () => {
// 更新当前项
const index = state.opened.findIndex(item => item.fullPath === state.current);
let page = state.opened[index];
page.params = params || page.params;
page.query = query || page.query;
page.fullPath = fullPath || page.fullPath;
page.meta = meta || page.meta;
state.opened.splice(index, 1, page);
// 持久化
await dispatch('opened2db');
// end
resolve();
}, 0);
});
},
/**
* @description 新增一个 tag (打开一个页面)
* @param {Object} param new tag info
*/
add ({ state, commit, dispatch }, { tag, params, query, fullPath }) {
return new Promise(async resolve => {
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
let newTag = tag;
newTag.params = params || newTag.params;
newTag.query = query || newTag.query;
newTag.fullPath = fullPath || newTag.fullPath;
// 添加进当前显示的页面数组
state.opened.push(newTag);
// 如果这个页面需要缓存 将其添加到缓存设置
if (isKeepAlive(newTag)) {
commit('keepAlivePush', tag.name);
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 打开一个新的页面
* @param {Object} param 从路由钩子的 to 对象上获取 { name, params, query, fullPath } 路由信息
*/
open ({ state, commit, dispatch }, { name, params, query, fullPath }) {
return new Promise(async resolve => {
// 已经打开的页面
let opened = state.opened;
// 判断此页面是否已经打开 并且记录位置
let pageOpenedIndex = 0;
const pageOpened = opened.find((page, index) => {
const same = page.fullPath === fullPath;
pageOpenedIndex = same ? index : pageOpenedIndex;
return same;
if (pageOpened) {
// 页面以前打开过
await dispatch('openedUpdate', {
index: pageOpenedIndex,
params,
query,
fullPath
});
if (pageOpened) {
// 页面以前打开过
await dispatch('openedUpdate', {
index: pageOpenedIndex,
} else {
// 页面以前没有打开过
let page = state.pool.find(t => t.name === name);
// 如果这里没有找到 page 代表这个路由虽然在框架内 但是不参与标签页显示
if (page) {
await dispatch('add', {
tag: Object.assign({}, page),
params,
query,
fullPath
});
} else {
// 页面以前没有打开过
let page = state.pool.find(t => t.name === name);
// 如果这里没有找到 page 代表这个路由虽然在框架内 但是不参与标签页显示
if (page) {
await dispatch('add', {
tag: Object.assign({}, page),
params,
query,
fullPath
});
}
}
commit('currentSet', fullPath);
// end
resolve();
});
},
/**
* @description 关闭一个 tag (关闭一个页面)
* @param {Object} param { tagName: 要关闭的标签名字 }
*/
close ({ state, commit, dispatch }, { tagName }) {
return new Promise(async resolve => {
// 下个新的页面
let newPage = state.opened[0];
const isCurrent = state.current === tagName;
// 如果关闭的页面就是当前显示的页面
if (isCurrent) {
// 去找一个新的页面
let len = state.opened.length;
for (let i = 0; i < len; i++) {
if (state.opened[i].fullPath === tagName) {
// 是否只剩最后一个,是则跳首页
if (len > 1) {
// 如果是最后一个,则向前一个跳,否则向下一个跳
if (i === len - 1) {
newPage = state.opened[i - 1];
} else {
newPage = state.opened[i + 1];
}
}
commit('currentSet', fullPath);
// end
resolve();
});
},
/**
* @description 关闭一个 tag (关闭一个页面)
* @param {Object} param { tagName: 要关闭的标签名字 }
*/
close({ state, commit, dispatch }, { tagName }) {
return new Promise(async resolve => {
// 下个新的页面
let newPage = state.opened[0];
const isCurrent = state.current === tagName;
// 如果关闭的页面就是当前显示的页面
if (isCurrent) {
// 去找一个新的页面
let len = state.opened.length;
for (let i = 0; i < len; i++) {
if (state.opened[i].fullPath === tagName) {
// 是否只剩最后一个,是则跳首页
if (len > 1) {
// 如果是最后一个,则向前一个跳,否则向下一个跳
if (i === len - 1) {
newPage = state.opened[i - 1];
} else {
newPage = {};
newPage = state.opened[i + 1];
}
break;
} else {
newPage = {};
}
break;
}
}
// 找到这个页面在已经打开的数据里是第几个
const index = state.opened.findIndex(page => page.fullPath === tagName);
if (index >= 0) {
// 如果这个页面是缓存的页面 将其在缓存设置中删除
commit('keepAliveRemove', state.opened[index].name);
// 更新数据 删除关闭的页面
state.opened.splice(index, 1);
}
// 持久化
await dispatch('opened2db');
// 最后需要判断是否需要跳到首页
if (isCurrent) {
const { name = 'index', params = {}, query = {} } = newPage;
let routerObj = {
name,
params,
query
};
$nuxt.$router.push(routerObj, () => {});
}
// end
resolve();
});
},
/**
* @description 关闭当前标签左边的标签
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeLeft ({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current;
let currentIndex = 0;
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index;
}
});
if (currentIndex > 0) {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name));
}
state.current = pageAim;
if ($nuxt.$router.fullPath !== pageAim) {
$nuxt.$router.push(pageAim);
}
// 找到这个页面在已经打开的数据里是第几个
const index = state.opened.findIndex(page => page.fullPath === tagName);
if (index >= 0) {
// 如果这个页面是缓存的页面 将其在缓存设置中删除
commit('keepAliveRemove', state.opened[index].name);
// 更新数据 删除关闭的页面
state.opened.splice(index, 1);
}
// 持久化
await dispatch('opened2db');
// 最后需要判断是否需要跳到首页
if (isCurrent) {
const { name = 'index', params = {}, query = {} } = newPage;
let routerObj = {
name,
params,
query
};
$nuxt.$router.push(routerObj, () => { });
}
// end
resolve();
});
},
/**
* @description 关闭当前标签左边的标签
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeLeft({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current;
let currentIndex = 0;
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index;
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 关闭当前标签右边的标签
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeRight ({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current;
let currentIndex = 0;
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index;
}
});
if (currentIndex > 0) {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name));
// 设置当前的页面
state.current = pageAim;
if ($nuxt.$router.fullPath !== pageAim) {
$nuxt.$router.push(pageAim);
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name));
}
if (state.opened.length == 2) {
state.opened.splice(0, 1);
}
state.current = pageAim;
if ($nuxt.$router.fullPath !== pageAim) {
$nuxt.$router.push(pageAim);
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 关闭当前标签右边的标签
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeRight({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current;
let currentIndex = 0;
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index;
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 关闭当前激活之外的 tag
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeOther ({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current;
let currentIndex = 0;
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index;
}
});
// 删除打开的页面数据 并更新缓存设置
if (currentIndex === 0) {
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name));
} else {
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name));
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name));
}
// 设置新的页面
state.current = pageAim;
if ($nuxt.$router.fullPath !== pageAim) {
$nuxt.$router.push(pageAim);
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name));
// 设置当前的页面
state.current = pageAim;
if ($nuxt.$router.fullPath !== pageAim) {
$nuxt.$router.push(pageAim);
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 关闭当前激活之外的 tag
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeOther({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current;
let currentIndex = 0;
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index;
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 关闭所有 tag
* @param {Object} state vuex state
*/
closeAll ({ state, commit, dispatch }) {
return new Promise(async resolve => {
// 删除打开的页面 并在缓存设置中删除
// 删除打开的页面数据 并更新缓存设置
if (currentIndex === 0) {
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name));
// 持久化
await dispatch('opened2db');
// 关闭所有的标签页后需要判断一次现在是不是在首页
if ($nuxt.$router.name !== 'index') {
$nuxt.$router.push({
name: 'index'
}, () => {});
}
// end
resolve();
});
}
} else {
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name));
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name));
}
if (state.opened.length == 2) {
state.opened.splice(0, 1);
}
// 设置新的页面
state.current = pageAim;
if ($nuxt.$router.fullPath !== pageAim) {
$nuxt.$router.push(pageAim);
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 关闭所有 tag
* @param {Object} state vuex state
*/
closeAll({ state, commit, dispatch }) {
return new Promise(async resolve => {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(0).forEach(({ name }) => commit('keepAliveRemove', name));
// 持久化
await dispatch('opened2db');
// 关闭所有的标签页后需要判断一次现在是不是在首页
// if ($nuxt.$router.name !== 'index') {
// $nuxt.$router.push({
// name: 'index'
// }, () => { });
// }
// end
resolve();
});
}
}
export const mutations={
/**
* @class keepAlive
* @description 从已经打开的页面记录中更新需要缓存的页面记录
* @param {Object} state vuex state
*/
keepAliveRefresh (state) {
state.keepAlive = state.opened.filter(item => isKeepAlive(item)).map(e => e.name);
},
/**
* @description 删除一个页面的缓存设置
* @param {Object} state vuex state
* @param {String} name name
*/
keepAliveRemove (state, name) {
const list = [ ...state.keepAlive ];
const index = list.findIndex(item => item === name);
export const mutations = {
/**
* @class keepAlive
* @description 从已经打开的页面记录中更新需要缓存的页面记录
* @param {Object} state vuex state
*/
keepAliveRefresh(state) {
state.keepAlive = state.opened.filter(item => isKeepAlive(item)).map(e => e.name);
},
/**
* @description 删除一个页面的缓存设置
* @param {Object} state vuex state
* @param {String} name name
*/
keepAliveRemove(state, name) {
const list = [...state.keepAlive];
const index = list.findIndex(item => item === name);
if (index !== -1) {
list.splice(index, 1);
state.keepAlive = list;
}
if (state.opened.length == 2) {
state.opened.splice(0, 1);
}
if (index !== -1) {
list.splice(index, 1);
state.keepAlive = list;
}
},
/**
* @description 增加一个页面的缓存设置
* @param {Object} state vuex state
* @param {String} name name
*/
keepAlivePush (state, name) {
const keep = [ ...state.keepAlive ];
keep.push(name);
state.keepAlive = keep;
},
/**
* @description 清空页面缓存设置
* @param {Object} state vuex state
*/
keepAliveClean (state) {
state.keepAlive = [];
},
/**
* @class current
* @description 设置当前激活的页面 fullPath
* @param {Object} state vuex state
* @param {String} fullPath new fullPath
*/
currentSet (state, fullPath) {
state.current = fullPath;
},
/**
* @class pool
* @description 保存 pool (候选池)
* @param {Object} state vuex state
* @param {Array} routes routes
*/
init (state, routes) {
const pool = [];
const push = function (routes) {
routes.forEach(route => {
if (route.children) {
push(route.children);
} else {
if (!route.hidden) {
const { meta, name, path } = route;
pool.push({ meta, name, path });
}
},
/**
* @description 增加一个页面的缓存设置
* @param {Object} state vuex state
* @param {String} name name
*/
keepAlivePush(state, name) {
const keep = [...state.keepAlive];
keep.push(name);
state.keepAlive = keep;
},
/**
* @description 清空页面缓存设置
* @param {Object} state vuex state
*/
keepAliveClean(state) {
state.keepAlive = [];
},
/**
* @class current
* @description 设置当前激活的页面 fullPath
* @param {Object} state vuex state
* @param {String} fullPath new fullPath
*/
currentSet(state, fullPath) {
state.current = fullPath;
},
/**
* @class pool
* @description 保存 pool (候选池)
* @param {Object} state vuex state
* @param {Array} routes routes
*/
init(state, routes) {
const pool = [];
const push = function (routes) {
routes.forEach(route => {
if (route.children) {
push(route.children);
} else {
if (!route.hidden) {
const { meta, name, path } = route;
pool.push({ meta, name, path });
}
})
};
push(routes);
state.pool = pool;
}
}
})
};
push(routes);
state.pool = pool;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment