Vue开发实例(十)Tabs标签页打开、关闭与路由之间的关系

创建标签页

  • 一、创建标签页
  • 二、点击菜单展示新标签页
    • 1、将标签数据作为全局使用
    • 2、菜单点击增加标签页
    • 3、处理重复标签
    • 4、关闭标签页
  • 三、点击标签页操作
    • 问题1:点击标签页选中菜单进行高亮展示
    • 问题2:点击标签页路由也要跳转
  • 四、解决bug


先展示最终效果
在这里插入图片描述

一、创建标签页

  1. 创建一个Tabs/index.vue页面
<template>
  <div>
    <el-tabs v-model="editableTabsValue" type="card" closable>
      <el-tab-pane
        :key="item.name"
        v-for="item in editableTabs"
        :label="item.title"
        :name="item.name"
      >
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
export default {
  name: "Tabss",
  data() {
    return {
      editableTabsValue: "1",
      editableTabs: [
        {
          title: "首页",
          name: "1",
          content: "首页",
        },
        {
          title: "Tab 1",
          name: "2",
          content: "Tab 1 content",
        },
        {
          title: "Tab 2",
          name: "3",
          content: "Tab 2 content",
        },
      ],
      tabIndex: 1,
    };
  },
};
</script>

<style scoped>
div{
  height: auto;
}
</style>
  1. 修改Index.vue页面,在页面的路由锚点 router-view上方引入此页面
    在这里插入图片描述
    页面效果
    在这里插入图片描述

二、点击菜单展示新标签页

1、将标签数据作为全局使用

(1)将数据放到store.js中,作为全局

import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from './module/moduleA.js';
import moduleB from './module/moduleB.js';

Vue.use(Vuex)

const state = {
  username: '牛牛',
  userState: 0,
  menu_data: [],
  isLoadRoute: false,
  editableTabsValue: '1',
  editableTabs: [
    {
      title: '首页',
      name: '首页',
      content: '首页'
    },
    {
      title: 'Tab 1',
      name: '2',
      content: 'Tab 1 content'
    },
    {
      title: 'Tab 2',
      name: '3',
      content: 'Tab 2 content'
    }
  ]
}
const mutations = {
  setLoadRoute(state, data) {
    state.isLoadRoute = data
  },
  setUser(state, name) {
    state.username = name
  },
  setUserState(state, data) {
    state.userState += data
  },
  setMenuData(state, data) {
    state.menu_data = data
  },

}
const getters = {
  getUserState(state) {
    let data;
    if (state.userState == 0) {
      data = '无效'
    } else {
      data = state.userState + '级'
    }
    return data;
  }
}
const modules = {
  a: moduleA,
  b: moduleB
}

export default new Vuex.Store({
  state,
  mutations,
  getters,
  modules
})

(2)Tabs/index.vue 中的这两个数据 editableTabsValueeditableTabs 就从store中获取

注意:

  • 如果你的在data中这样写,可能会无法正常显示,建议用computed 方式来写。
<template>
  <div>
    <el-tabs v-model="editableTabsValue" type="card" closable>
      <el-tab-pane
        :key="item.name"
        v-for="item in editableTabs"
        :label="item.title"
        :name="item.name"
      >
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
export default {
  name: "Tabs",
  data() {
    return {};
  },
  computed: {
    editableTabsValue: {
      get() {
        return this.$store.state.editableTabsValue;
      },
      set(val) {
        this.$store.state.editableTabsValue = val;
      },
    },
    editableTabs: {
      get() {
        return this.$store.state.editableTabs;
      },
      set(val) {
        this.$store.state.editableTabs = val;
      },
    },
  },
};
</script>

<style scoped>
div {
  height: auto;
}
</style>

页面效果是一样的
在这里插入图片描述

2、菜单点击增加标签页

(1)在 store/index.js 中将写死的数据editableTabs 内容删除,只剩下首页的那条
(2)在mutations添加 editableTabs 数据变更的方法 addEditableTabs,因为我定义的菜单数据的时候,没有title属性,所以这里我都用title来代表

参考代码:

import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from './module/moduleA.js';
import moduleB from './module/moduleB.js';

Vue.use(Vuex)

const state = {
  username: '牛牛',
  userState: 0,
  menu_data: [],
  isLoadRoute: false,
  editableTabsValue: '1',
  editableTabs: [
    {
      title: '首页',
      name: '首页',
      content: '首页'
    }
  ]
}
const mutations = {
  setLoadRoute(state, data) {
    state.isLoadRoute = data
  },
  setUser(state, name) {
    state.username = name
  },
  setUserState(state, data) {
    state.userState += data
  },
  setMenuData(state, data) {
    state.menu_data = data
  },
  addEditableTabs(state, tab) {
    state.editableTabs.push({
      title: tab.name,
      name: tab.name
    })
    state.editableTabsValue = tab.name
  }
}
const getters = {
  getUserState(state) {
    let data;
    if (state.userState == 0) {
      data = '无效'
    } else {
      data = state.userState + '级'
    }
    return data;
  }
}
const modules = {
  a: moduleA,
  b: moduleB
}

export default new Vuex.Store({
  state,
  mutations,
  getters,
  modules
})

(3)给Aside/index.vue菜单增加点事件,selectMenu方法

<template>
  <div style="height: 100%">
    <el-menu
      background-color="#545c64"
      text-color="#ffffff"
      active-text-color="#ffd04b"
      class="el-menu-vertical-demo"
      router
    >
      <el-menu-item
        :index="item.path"
        v-for="item in menu_data"
        :key="item.name"
        @click="selectMenu(item)"
      >
        <i :class="item.icon"></i>{{ item.name }}
      </el-menu-item>
    </el-menu>
  </div>
</template>

<script>
export default {
  name: "Aside",
  data() {
    return {};
  },
  computed: {
    menu_data: {
      get() {
        return this.$store.state.menu_data;
      },
    },
  },
  methods: {
    selectMenu(item) {
      this.$store.commit("addEditableTabs", item);
    },
  },
};
</script>

<style scoped>
.el-icon-location,
.el-icon-document,
.el-icon-setting {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
</style>

页面效果
在这里插入图片描述
问题:出现重复菜单名称标签

3、处理重复标签

store/index.js文件中的addEditableTabs 中判断,如果数据中已经有了,则不重复添加,只需切换即可
在这里插入图片描述

页面效果
在这里插入图片描述
现在就只有两个标签了,目前展示正常,但是没法关闭

4、关闭标签页

标签页添加关闭事件

el-tabs标签中添加 @tab-remove="removeTab",在method添加对应的方法

<template>
  <div>
    <el-tabs
      v-model="editableTabsValue"
      type="card"
      closable
      @tab-remove="removeTab"
    >
      <el-tab-pane
        :key="item.name"
        v-for="item in editableTabs"
        :label="item.title"
        :name="item.name"
      >
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
export default {
  name: "Tabs",
  data() {
    return {};
  },
  methods: {
    removeTab(targetName) {
      let tabs = this.editableTabs;
      let activeName = this.editableTabsValue;
      if (activeName === targetName) {
        tabs.forEach((tab, index) => {
          if (tab.name === targetName) {
            let nextTab = tabs[index + 1] || tabs[index - 1];
            if (nextTab) {
              activeName = nextTab.name;
            }
          }
        });
      }
      this.editableTabsValue = activeName;
      this.editableTabs = tabs.filter((tab) => tab.name !== targetName);
    },
  },
  computed: {
    editableTabsValue: {
      get() {
        return this.$store.state.editableTabsValue;
      },
      set(val) {
        this.$store.state.editableTabsValue = val;
      },
    },
    editableTabs: {
      get() {
        return this.$store.state.editableTabs;
      },
      set(val) {
        this.$store.state.editableTabs = val;
      },
    },
  },
};
</script>

<style scoped>
div {
  height: auto;
}
</style>

页面效果
在这里插入图片描述

问题:

  1. 选中菜单,侧边栏没有进行对应的高亮展示
  2. 关闭了“一级菜单2”,但是页面内容还停留在“一级菜单2”,其实就是路由没有变

三、点击标签页操作

问题1:点击标签页选中菜单进行高亮展示

  1. 在Aside/index.vue中给 el-menu 设置属性 default-active
:default-active="this.$store.state.editableTabsValue"
  1. 将原来代码el-menu-item的index设置为"item.name"
:index="item.name"
  1. 加入路由跳转代码

因原来菜单点击,会根据index属性来跳转,index原来是path(路由地址),现在index属性更改为name了,则跳转不会生效,修改原来的router.js的代码,动态创建路由加入name属性(name:item.name),方便跳转。

修改router/index.js 代码

let oRouters = router.options.routes;
const buildRouter = ()=>{
    let data = store.state.menu_data;
    data.forEach(item=>{
        let new_router = {
            path:item.path,
            name:item.name,
            component:() => import('./components/'+item.component+'.vue')
        }
        oRouters[0].children.push(new_router);

    })
    router.addRoutes(oRouters)
}

Aside/index.vue的 selectMenu方法中,加入路由跳转代码(根据name跳转),仅需一行代码即可。

selectMenu(item){
	//点击菜单跳转路由
    this.$router.push({name:item.name})
    this.$store.commit("addEditableTabs",item);
}

页面效果,可以实现点击标签页,菜单跟着高亮显示了
在这里插入图片描述
Aside/index.vue 页面代码

<template>
  <div style="height: 100%">
    <el-menu
      background-color="#545c64"
      text-color="#ffffff"
      active-text-color="#ffd04b"
      class="el-menu-vertical-demo"
      router
      :default-active="this.$store.state.editableTabsValue"
    >
      <el-menu-item
        :index="item.name"
        v-for="item in menu_data"
        :key="item.name"
        @click="selectMenu(item)"
      >
        <i :class="item.icon"></i>{{ item.name }}
      </el-menu-item>
    </el-menu>
  </div>
</template>

<script>
export default {
  name: "Aside",
  data() {
    return {};
  },
  computed: {
    menu_data: {
      get() {
        return this.$store.state.menu_data;
      },
    },
  },
  methods: {
    selectMenu(item) {
      //点击菜单跳转路由
      this.$router.push({ name: item.name });
      this.$store.commit("addEditableTabs", item);
    },
  },
};
</script>

<style scoped>
.el-icon-location,
.el-icon-document,
.el-icon-setting {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
</style>

问题2:点击标签页路由也要跳转

上面遗留的问题2,点击标签页,标签页下方的页面没有跟着跳转,下面修改这个问题

  1. 在Tabs页面的 el-tabs 添加 tab-click 事件
  2. 添加方法,利用路由的name来跳转
<template>
  <div>
    <el-tabs
      v-model="editableTabsValue"
      type="card"
      closable
      @tab-remove="removeTab"
      @tab-click="clickTab"
    >
      <el-tab-pane
        :key="item.name"
        v-for="item in editableTabs"
        :label="item.title"
        :name="item.name"
      >
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
export default {
  name: "Tabs",
  data() {
    return {};
  },
  methods: {
    removeTab(targetName) {
      let tabs = this.editableTabs;
      let activeName = this.editableTabsValue;
      if (activeName === targetName) {
        tabs.forEach((tab, index) => {
          if (tab.name === targetName) {
            let nextTab = tabs[index + 1] || tabs[index - 1];
            if (nextTab) {
              activeName = nextTab.name;
            }
          }
        });
      }
      this.editableTabsValue = activeName;
      this.editableTabs = tabs.filter((tab) => tab.name !== targetName);
    },
    clickTab(target) {
      this.$router.push({ name: target.name });
    },
  },
  computed: {
    editableTabsValue: {
      get() {
        return this.$store.state.editableTabsValue;
      },
      set(val) {
        this.$store.state.editableTabsValue = val;
      },
    },
    editableTabs: {
      get() {
        return this.$store.state.editableTabs;
      },
      set(val) {
        this.$store.state.editableTabs = val;
      },
    },
  },
};
</script>

<style scoped>
div {
  height: auto;
}
</style>

效果展示
在这里插入图片描述

四、解决bug

  1. 关闭菜单后,菜单对应的路由没有跟着跳转
    仅需在关闭标签的方法removeTab,最后加上以下代码
this.$router.push({name:activeName})
  1. 首页不允许关闭
    在关闭标签的方法removeTab ,执行关闭之前,加入以下代码
if(targetName=='首页'){
    return ;
}
  1. 完整removeTab 代码
removeTab(targetName) {
   let tabs = this.editableTabs;
   let activeName = this.editableTabsValue;
   if(targetName=='首页'){
       return ;
   }
   if (activeName === targetName) {
       tabs.forEach((tab, index) => {
           if (tab.name === targetName) {
               let nextTab = tabs[index + 1] || tabs[index - 1];
               if (nextTab) {
                   activeName = nextTab.name;
               }
           }
       });
   }

   this.editableTabsValue = activeName;
   this.editableTabs = tabs.filter(tab => tab.name !== targetName);

   this.$router.push({name:activeName})
}
  1. 还有一个潜藏的bug就是打开、关闭的顺序问题,先关闭前面的菜单会报错,后面解决

在这里插入图片描述报错代码如下

Uncaught runtime errors:
 Avoided redundant navigation to current location: "/index/menu2".
 NavigationDuplicated: Avoided redundant navigation to current location: "/index/menu2".
    at createRouterError (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:1720:15)
    at createNavigationDuplicatedError (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:1708:15)
    at HTML5History.confirmTransition (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:1946:18)
    at HTML5History.transitionTo (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:1887:8)
    at HTML5History.push (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2165:10)
    at eval (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2510:22)
    at new Promise (<anonymous>)
    at VueRouter.push (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2509:12)
    at VueComponent.removeTab (webpack-internal:///./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/components/Tabs/index.vue?vue&type=script&lang=js:29:20)
    at invokeWithErrorHandling (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:2903:26)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/436321.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

项目管理工具进度猫:自我管理的应用

在飞速发展的现代社会中&#xff0c;每个人都面临着巨大的竞争压力&#xff0c;如何在这激烈的环境中脱颖而出&#xff0c;实现个人的成长与成功&#xff1f;答案就在我们的日常行为中——自我管理。 一、自我管理的定义 自我管理&#xff0c;简单来说&#xff0c;就是对自己…

mysql8安装配置(最新版)

目录 一、下载mysql8 二、安装mysql8 三、配置mysql 一、下载mysql8 下载链接&#xff1a;https://pan.quark.cn/s/58d9072e51c4 二、安装mysql8 双击msi文件 选择custom 根据所需选择组件 修改安装路径 选中execute&#xff0c;安装&#xff0c;弹出提示安装VS的提示框之后…

LT6813/ADBMS1818底层驱动---均衡控制

1、LT6813采用内部均衡的原理 2、平衡控制结构体 根据数据库中读取的控制值设置平衡。要为单元设置平衡&#xff0c;必须将相应的位写入配置寄存器中。LTC 驱动程序仅执行数据库中 BMS 写入的数据。 参数 ltc_stateLTC 状态机的状态pSpi接口指向 SPI 配置的指针pTxBuff &…

Android SDK2 (实操三个小目标)

书接上回&#xff1a;Android SDK 1&#xff08;概览&#xff09;-CSDN博客 今天讲讲三个实际练手内容&#xff0c;用的是瑞星微的sdk。 1 实操编译Android.bp 首先还是感叹下&#xff0c;现在的系统真的越搞越复杂&#xff0c;最早只有gcc&#xff0c;后面多了make&#xf…

2.3_9 读者-写者问题

2.3_9 读者-写者问题 &#xff08;一&#xff09;问题描述 有读者和写者两组并发进程&#xff0c;共享一个文件&#xff0c;当两个或两个以上的读进程同时访问共享数据时不会产生副作用&#xff0c;但若某个写进程和其他进程&#xff08;读进程或写进程&#xff09;同时访问共…

【nvm】nvm的安装和使用

简言 nvm(nvm-windows)的安装和使用。 nvm 允许你通过命令行快速安装和使用不同版本的 node。 nvm 适用于任何符合 POSIX 标准的 shell&#xff08;sh、dash、ksh、zsh、bash&#xff09;&#xff0c;尤其适用于以下平台&#xff1a;Unix、macOS 和 windows WSL。 不过 nvm 在…

安全防御第七次作业

拓扑图如图所示&#xff1a; 问题&#xff1a;在FW7和FW8之间建立一条IPSEC通道保证10.0.2.0/24网段 可以正常访问到192.168.1.0/24 注&#xff1a;基础配置我在此省略了 一、NAT配置 FW4&#xff1a; FW6&#xff1a; 二、在FW4上做服务器映射 三、配置IPSEC FW5&#xff…

用xshell7连接服务器,读取后台日志

有时候前端需要读取一些后台日志&#xff0c;比如&#xff0c;有时候接一些验证码啥的 或者有时候前后端不分离时&#xff0c;前端上线项目 先讲一下怎么用密码方式连接服务器 密码方式连接服务器 第一步&#xff0c;安装xshell&#xff0c;在新建会话中填写主机&#xff0…

两两交换链表中的节点+力扣

题目 题目链接 . - 力扣&#xff08;LeetCode&#xff09; 题目描述 代码实现 class Solution { public:ListNode* swapPairs(ListNode* head) {if(head nullptr || head->next nullptr) return head;ListNode *tmpHead swapPairs(head->next->next);ListNode …

企微hook源码

企微hook源码已经在QQ群内开源。速度进群下载&#xff0c;避免和谐。 QQ群&#xff1a;649480745

AI应用开发-python对MySQL数据的常见使用

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享&#xff0c;包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概…

如何做代币分析:以 ARB 币为例

作者&#xff1a;lesleyfootprint.network 编译&#xff1a;mingfootprint.network 数据源&#xff1a;ARB 代币仪表板 &#xff08;仅包括以太坊数据&#xff09; 在加密货币和数字资产领域&#xff0c;代币分析起着至关重要的作用。代币分析指的是深入研究与代币相关的数据…

GitHub Pages部署静态页面

GitHub Pages是GitHub提供的静态页面托管服务&#xff0c;可以用来托管个人博客、项目文档等静态页面。GitHub Pages支持Jekyll&#xff0c;可以使用Jekyll构建博客&#xff0c;也可以使用其他静态页面生成器。现在GitHub Pages也在公测通过工作流部署静态页面&#xff0c;可以…

【趣玩一下】StreamDiffusion一秒100张!实时生成二次元老婆照!

源代码 https://github.com/cumulo-autumn/StreamDiffusion 基础原理 首先Stream Batch&#xff0c;是将原来顺序的去噪步骤改为批量化处理。允许在一个批处理中&#xff0c;每幅图像处于去噪流程的不同阶段。 如此一来&#xff0c;可以大大减少UNet推理次数&#xff0c;显著…

【SQL】1321. 餐馆营业额变化增长(窗口函数rows between 、range between;DATEDIFF()函数)

前述 窗口函数相关知识推荐阅读&#xff1a; 通俗易懂的学会&#xff1a;SQL窗口函数 窗口函数rows between 、range between的使用 MySQL中的DATEDIFF()函数 mysql data类型的加减 常用函数&#xff1a; ROUND() 函数&#xff1a;用于将数值四舍五入到指定的小数位数。FLOO…

Python爬虫——scrapy-2

目录 scrapy简介 安装ipython 基本使用 访问百度 总结 scrapy简介 scrapy shell是Scrapy框架提供的一个交互式命令行工具&#xff0c;用于快速调试和测试Scrapy爬虫。它能够加载Scrapy项目的设置和爬虫代码&#xff0c;并提供一个交互式环境&#xff0c;可以在其中执行Scra…

云计算项目七:jump-server安装部署

jump-server安装部署 配置清单 jumpserver概述 Jumpserver是一款开源的堡垒机&#xff0c;可使系统的管理员和开发人员安全的连接到企业内部服务器上执行操作&#xff0c;并且支持大部分操作系统&#xff0c;是一款非常安全的远程连接工具 常见支持的系统 CentOS, RedHat, …

GNURadio+USRP+OFDM实现文件传输

文章目录 前言一、发送端1、参数配置1&#xff09;Random Source2&#xff09;stream to Tagged stream3&#xff09;Stream CRC324&#xff09;Protocol Formatter5&#xff09;Repack Bits6&#xff09;Virtual Sink7&#xff09;Chunks to Symbols8&#xff09;Tagged Strea…

关于装载类子系统

装载类子系统 类加载器字节码调节器类加载运行时数据区 类加载器 将class文件加载进jvm的方法去&#xff0c;并在方法去中创建一个java.lang.Class对象作为外界访问这个类的接口。实现这个动作的代码模块称为类加载器。 类加载器分类 启动类加载器&#xff08;Bootstrap C…

keycloak18.0.0==本地源码启动

github下载源码&#xff0c; 版本18.0.0 java和maven的版本如下 E:\keycloak-18.0.0>java -version java version "21.0.1" 2023-10-17 LTS Java(TM) SE Runtime Environment (build 21.0.112-LTS-29) Java HotSpot(TM) 64-Bit Server VM (build 21.0.112-LTS-…