1. Proceso general
2. Conocimiento de Vue3 utilizado
1. Comunicación de componentes
(1) Padre a hijo
En vue3, los componentes principales utilizan enlaces y accesorios para pasar valores a los componentes secundarios.
Debido a que la matriz de pestañas debe colocarse en la página principal,
data(){
return {
tabs: []
}
},
Entonces, la barra superior necesita obtener la matriz de pestañas de la página principal.
Primero defina los accesorios en la pestaña para recibir
props:{
tabs: Array // 声明一个 props,指定数据类型为数组
},
Luego vincúlelo con el carácter de enlace en la etiqueta de la página secundaria en la página principal.
<NavBar :tabs="tabs" ></NavBar>
De esta manera, la matriz de pestañas de la página principal se puede pasar a la página secundaria.
(2) El Hijo da al Padre
Debido a que hay una ruta en la página secundaria para saltar a una nueva página, debe agregar una pestaña, es decir, agregar la nueva página como una pestaña a la matriz de pestañas, y la matriz de pestañas se coloca en la página principal, por lo que el niño necesita pasar el valor al padre.
El niño transfiere el valor al padre llamando a un método usando this.$emit("nombre de comunicación", datos)
Por ejemplo, la operación de agregar una pestaña aquí es
this.$emit("addtab",tab)
Luego use @ en la etiqueta secundaria de la página principal para aceptar el nombre de la comunicación y vincular el método que se llamará.
<router-view @addtab="addTab"></router-view>
Al mismo tiempo, pase los datos al método como parámetro de datos.
addTab(data) {
//最简单的push操作,还没完成其它逻辑
this.tabs.push(data);
}
3. Implementar la lógica general.
1. En la página principal
(1) Escribe la lógica para agregar pestañas.
addTab(data) {
// this.tabs.push(data);
// 判断是否已存在相同的 title 和 route
const exists = this.tabs.some(tab => tab.title === data.title && tab.route === data.route);
if (!exists) {
this.tabs.forEach(tab => {
tab.selected = false;
});
this.tabs.push(data);
}else{
this.tabs.forEach(tab => {
tab.selected = tab.title === data.title && tab.route === data.route;
});
}
// 更新浏览器缓存
this.saveTabsToLocalStorage()
}
(2) Escribe la lógica para cerrar la pestaña.
closeTab(index) {
this.tabs.splice(index, 1); // 从数组中移除页签
if (this.tabs.length > 0) {
this.tabs.forEach(tab => {
tab.selected = false;
});
// 如果还有其他选项卡,跳转到最后一个选项卡的路由
const lastTab = this.tabs[this.tabs.length - 1];
this.$router.push(lastTab.route);
this.tabs[this.tabs.length - 1].selected=true;
} else {
// 如果没有选项卡了,跳转到默认的首页路由
this.$router.push("/1/C");
}
// 更新浏览器缓存
this.saveTabsToLocalStorage()
},
(3) Almacenar en caché la matriz de pestañas en el navegador y cargarla desde el caché
mounted() {
this.loadTabsFromLocalStorage();
},
methods:{
// 缓存到本地
saveTabsToLocalStorage() {
localStorage.setItem('tabs', JSON.stringify(this.tabs));
},
// 从缓存加载
loadTabsFromLocalStorage() {
const storedTabs = localStorage.getItem('tabs');
if (storedTabs) {
this.tabs = JSON.parse(storedTabs);
}
},
}
Almacene en caché los datos de la pestaña en el navegador. Cuando se actualiza la página, el estado de la pestaña conserva el estado actual y no se borrará.
(4) Comunicarse con la barra superior
<NavBar :tabs="tabs" @asideCollapse="collapse" @closetab="closeTab">
(5) Comunicarse con subpáginas que necesitan generar pestañas
<router-view @addtab="addTab"></router-view>
2. barra superior
(1) Pestaña de renderizado
<div class="top-bar">
<!-- 渲染页签 -->
<div
v-for="(tab, index) in tabs"
:key="index"
:class="['tab', { 'selected': tab.selected }]"
@click="switchTab(tab)"
>
{
{ tab.title }}
<span class="close-btn" @click.stop="closeTab(index)">×</span>
</div>
</div>
(2) Escribir estilo de pestaña
<style lang="scss" scoped>
.top-bar{
display: flex;
margin-left: 20px;
caret-color: transparent; /*去除鼠标光标*/
width: 100vw;
overflow-x: auto; /* 允许横向滚动 */
//overflow: hidden;
div:hover{
cursor:pointer;
}
div:not(:first-child){
margin-left: 10px;
}
div{
display: flex;
justify-content: center;
align-items: center;
padding: 5px;
font-weight: 500;
font-size: 14px;
color: #606266;
border: 1px solid #DCDFE6;
border-radius: 4px;
//width: 100%;
height: 30px;
white-space: nowrap; /* 防止内容换行 */
span{
width: 15px;
height: 15px;
margin-left: 4px;
display: flex;
align-items: center;
justify-content: center;
}
}
.tab{
background-color: #eeeeee;
span:hover{
background: linear-gradient(rgba(96, 98, 102, 0.1), rgba(96, 98, 102, 0.1)); /* 在悬停时更改透明度 */
}
}
.selected{
background-color: #c6fce5;
}
}
</style>
(3) Aceptar datos de la página principal
props:{
tabs: Array // 声明一个 props,指定数据类型为数组
},
(4) Enviar una solicitud para cerrar la pestaña de la página principal
// 关闭页签
closeTab(index) {
this.$emit("closetab",index)
},
3. Subpágina
(1) Enviar una solicitud para agregar una pestaña a la página principal
methods:{
addTab(tab){
this.$emit("addtab",tab)
}
}
(2) Solicitudes de vinculación de etiquetas con requisitos de enrutamiento de salto
Por ejemplo, elementos del menú.
<el-menu-item index="/1/C"
@click="addTab({
title: '模拟计算', // 页面标题
route: '/1/C', // 路由
selected: true // 设置选中状态
})"
>
4. Efecto de visualización
5. Posibles errores
1. Se ejecuta sin errores en el entorno local y se informará después de su implementación en el entorno de producción.
TypeError: No se pueden leer las propiedades de null (leyendo 'insertBefore' )
solución
(1) La matriz de pestañas de representación v-for en el componente de la barra superior NavBar no determina si las pestañas están vacías.
(2) Cambie vue a la versión ([email protected]) para solucionarlo.
npm i [email protected]