业务场景
微前端子应用间加tab,做到菜单切换
效果
涉及问题
因为这是加在每个子应用间,所以需要在每个子应用都加上tabs组件,切换的菜单如何在每个子应用更新?
处理方案
思路就是将我们点击的菜单保存到localStorage中,然后每个子应用去监听localStorage值的变化,从而更新tabs组件的值。
在资源文件中新建locale.js
export default function dispatchEventStroage () {
let signSetItem = localStorage.setItem
localStorage.setItem = function (key, val) {
let setEvent = new Event('setItemEvent')
setEvent.key = key
setEvent.newValue = val
window.dispatchEvent(setEvent)
signSetItem.apply(this, arguments)
}
}
在index.js中引用这个js,我这里是放在plugins文件夹下
import tool from '@/plugins/locale';
Vue.use(tool);
在App.vue加上tabs这个组件
<template>
<div class="app" @click="down">
<!-- 加载tabs组件 -->
<a-tabs
v-model="activeKey"
type="editable-card"
hideAdd
@edit="onEdit"
@change="onChange"
@contextmenu.prevent="open($event)"
>
<a-tab-pane
v-for="pane in initalItem"
:key="pane.key"
:tab="pane.title"
:closable="pane.closable"
>
<!-- 这里做的是自定义右键 -->
<ul
v-show="visible"
:style="{ left: left + 'px', top: top + 'px' }"
class="newcontextmenu"
>
<li @click="close">关闭标签</li>
<li @click="closeAll">关闭所有标签</li>
</ul>
</a-tab-pane>
</a-tabs>
<div class="app-main">
<router-view />
</div>
</div>
</template>
<script>
export default {
data() {
return {
activeKey: this.$route.path,
initalItem: JSON.parse(localStorage.getItem("initalItem")),
visible: false,
top: 0,
left: 0,
};
},
created() {},
mounted() {
let that = this;
// 监听localStorage的值的变化
this.$nextTick(function () {
window.addEventListener("setItemEvent", (e) => {
setTimeout(function () {
that.initalItem = JSON.parse(localStorage.getItem("initalItem"));
});
setTimeout(function () {
that.activeKey = that.$route.path;
});
});
});
},
methods: {
onEdit(targetKey, action) {
if (action == "remove") {
const initalItem = JSON.parse(localStorage.getItem("initalItem"));
initalItem.splice(
initalItem.findIndex((item) => item.key === targetKey),
1
);
localStorage.setItem("initalItem", JSON.stringify(initalItem));
this.initalItem = initalItem;
this.activeKey = initalItem[initalItem.length - 1].key;
this.$router.push(this.activeKey);
}
},
onChange(targetKey) {
const initalItem = JSON.parse(localStorage.getItem("initalItem"));
let data = initalItem.find((item) => item.key == targetKey);
this.$router.push({
path: targetKey,
query: data.query,
});
},
open(e) {
this.visible = false;
var x = e.pageX + 50;
var y = e.pageY;
this.top = y;
this.left = x;
this.visible = true;
},
down() {
this.visible = false;
},
close() {
const initalItem = JSON.parse(localStorage.getItem("initalItem"));
initalItem.splice(
initalItem.findIndex((item) => item.key === this.activeKey),
1
);
localStorage.setItem("initalItem", JSON.stringify(initalItem));
this.initalItem = initalItem;
this.activeKey = initalItem[initalItem.length - 1].key;
this.$router.push(this.activeKey);
},
closeAll() {
localStorage.setItem(
"initalItem",
JSON.stringify([
{
title: "首页",
key: "/index",
closable: false,
},
])
);
this.initalItem = [
{
title: "首页",
key: "/index",
closable: false,
},
];
this.activeKey = "/index";
this.$router.push("/index");
},
},
};
</script>
<style lang="less">
.newcontextmenu {
position: fixed;
border: 1px solid #ccc;
border-radius: 5px;
background: #fff;
li {
padding: 10px;
cursor: pointer;
}
}
</style>
修改router.js
//去重,后面点击的覆盖前面点击的(对应的key值)
function deWeight(arr) {
let map = new Map();
for(let item of arr){
map.set(item.key,item)
}
return [...map.values()];
}
router.beforeEach(async (to, from, next) => {
let array = JSON.parse(localStorage.getItem("initalItem"))?JSON.parse(localStorage.getItem("initalItem")):[]
if(to.path === '/index'){
array.push({
title: '首页',
key: to.path,
closable: false
})
}else{
array.push({
title: to.meta.title,
key: to.path,
query: to.query
})
}
localStorage.setItem("initalItem",JSON.stringify(deWeight(array)));
});
这是其中一个子应用的配置,另一个子应用也是相对应的配置。