• [vue3] 统一页面导航标签


     ✨✨个人主页:沫洺的主页

    📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 

                               📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏

                               📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏     

    💖💖如果文章对你有所帮助请留下三连✨✨

    🍔效果图

    🍟实现内容

    • 🎫ElementPuls页面布局(上上章)
    • 🎫动态菜单显示(上上章)
    • 🎫实现菜单折叠效果(上一章)
    • 🎫实现部分页面不使用整体框架(下一章)
    • 🎫统一页面导航标签(本章)

    🌭 统一页面导航标签

     🎑新建components/NavHead.vue

     🎑使用watch()侦听

     NavHead.vue

    1. <script setup lang="ts">
    2. import { ref, onMounted, watch } from 'vue'
    3. import { useRoute, useRouter } from "vue-router";
    4. import { appStore } from "@/store/appStore";
    5. import { storeToRefs } from "pinia";
    6. const route = useRoute();
    7. const router = useRouter();
    8. //watch() 侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
    9. watch(
    10. //监听什么对象(这里监听的是当前路由的路径)
    11. //当路径发生变化时,就执行回调函数
    12. () => route.path,
    13. //新值,老值,回调函数
    14. (newValue, oldValue) => {
    15. // newValue === oldValue
    16. console.log("新值: "+newValue, "老值: "+oldValue)
    17. },
    18. //深度监听对象中的所有属性
    19. { deep: true }
    20. )
    21. script>

     🎑App.vue中导入文件,并引用

     🎑看一下监听效果

     🎑 使用Tabs标签设置导航标签

     🎑 复制template和script标签的内容到NavHead.vue中查看效果

     🎑 对原有的代码进行改动,不需要的功能可以不要

     

     🎑 对代码进行改进(有注释可参考)

     NavHead.vue

    1. <script setup lang="ts">
    2. import { ref, onMounted, watch } from 'vue'
    3. import { useRoute, useRouter } from "vue-router";
    4. import { appStore } from "@/store/appStore";
    5. import { storeToRefs } from "pinia";
    6. const route = useRoute();
    7. const router = useRouter();
    8. //当前活动标签,默认显示name:'1'的元素
    9. const editableTabsValue = ref('1')
    10. //定义一个editableTabs数组,里边放了几个元素
    11. const editableTabs = ref([
    12. {
    13. title: 'Tab 1',
    14. name: '1',
    15. },
    16. {
    17. title: 'Tab 2',
    18. name: '2',
    19. },
    20. {
    21. title: 'Tab 3',
    22. name: '3',
    23. },
    24. ])
    25. //移除方法,当点击移除按钮时,这里的targetName就是所点击的元素的name
    26. const tabRemove = (targetName: string) => {
    27. //editableTabs.value就是 { title: 'Tab 1',name: '1',} 这样的元素
    28. let tabs = editableTabs.value;
    29. //过滤掉除所点击的元素以外的元素,也就是说没有过滤的就是要移除的元素
    30. editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
    31. //计算活动标签是哪一个
    32. //如果移除的是当前活动标签(元素),那么通过下面的逻辑进行高亮显示
    33. let activeName = editableTabsValue.value
    34. if (activeName === targetName) {
    35. // 对数组进行遍历找到当前活动标签的位置
    36. tabs.forEach((tab, index) => {
    37. if (tab.name === targetName) {
    38. // 找到之后取前后索引位置的元素
    39. //找离活动标签最近的标签,右边优先于左边显示
    40. const nextTab = tabs[index + 1] || tabs[index - 1]
    41. //如果nextTab存在就赋值,也就是如果右边没有就取左边的
    42. if (nextTab) {
    43. activeName = nextTab.name
    44. }
    45. }
    46. })
    47. // 给当前活动标签赋值新的name,进行高亮
    48. editableTabsValue.value = activeName
    49. }
    50. }
    51. //watch() 侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
    52. watch(
    53. //监听什么对象(这里监听的是当前路由的路径)
    54. //当路径发生变化时,就执行回调函数
    55. () => route.path,
    56. //新值,老值,回调函数
    57. (newValue, oldValue) => {
    58. // newValue === oldValue
    59. console.log("新值: "+newValue, "老值: "+oldValue)
    60. },
    61. //深度监听对象中的所有属性
    62. { deep: true }
    63. )
    64. script>

    • 📍将Tab标签和左边的Aside部分里的Menu菜单进行关联,也就是动态显示Tab标签页,当点击Menu菜单项时就会在Tab标签页中显示对应的标签页
    • 📍当点击菜单项时,Tab标签页中如果已经存在对应的标签页时,就不需要再添加标签页,保证其唯一性
    • 📍实现动态关联之后在Main部分中同样的显示Menu菜单项的内容(tab-change)
    • 📍默认显示首页标签页(当初始状态时,总要显示一个首页,因此首页就不需要移除按钮,作为初始化的数据显示)
    • 📍实现本地存储,当关闭网页后,再次访问所关闭的网页的路径,会通过本地存储恢复之前的状态信息,
    • 📍实现当页面信息发送改变时,切换标签页时信息不被消除(场景一)
    • 📍实现强制回退路径,页面初始化(场景二)

     🎑 NavHead.vue

    1. <script setup lang="ts">
    2. import { ref, onMounted, watch } from 'vue'
    3. import { useRoute, useRouter } from "vue-router";
    4. import { appStore } from "@/store/appStore";
    5. import { storeToRefs } from "pinia";
    6. let { editableTabsValue, editableTabs } = storeToRefs(appStore());
    7. const route = useRoute();
    8. const router = useRouter();
    9. //移除方法,当点击移除按钮时,这里的targetName就是所点击的元素的name
    10. const tabRemove = (targetName: string) => {
    11. //editableTabs.value就是 { title: 'Tab 1',name: '1',} 这样的元素
    12. let tabs = editableTabs.value;
    13. //过滤掉除所点击的元素以外的元素,也就是说没有过滤的就是要移除的元素
    14. editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
    15. //计算活动标签是哪一个
    16. //如果移除的是当前活动标签(元素),那么通过下面的逻辑进行高亮显示
    17. let activeName = editableTabsValue.value
    18. if (activeName === targetName) {
    19. // 对数组进行遍历找到当前活动标签的位置
    20. tabs.forEach((tab, index) => {
    21. if (tab.name === targetName) {
    22. // 找到之后取前后索引位置的元素
    23. //找离活动标签最近的标签,右边优先于左边显示
    24. const nextTab = tabs[index + 1] || tabs[index - 1]
    25. //如果nextTab存在就赋值,也就是如果右边没有就取左边的
    26. if (nextTab) {
    27. activeName = nextTab.name
    28. }
    29. }
    30. })
    31. // 给当前活动标签赋值新的name,进行高亮
    32. editableTabsValue.value = activeName
    33. }
    34. }
    35. const tabAdd = (route: any) => {
    36. //先判断标签页是否已经存在,如果不存在才添加,findIndex判断索引
    37. //当前路由的name是否和标签页数组item的name相等
    38. //返回索引,如果索引为-1,则表示不存在
    39. var index = editableTabs.value.findIndex(item => item.name === route.name);
    40. if (index === -1) {
    41. //通过push向数组中添加一个元素对象
    42. editableTabs.value.push({
    43. //通过路由Menu获取菜单项的title和name
    44. title: route.meta.title,
    45. name: route.name,
    46. //显示移除按钮
    47. close: true,
    48. });
    49. }
    50. //新添加的Tab标签页高亮
    51. editableTabsValue.value = route.name;
    52. }
    53. const tabChange = (name: any) => {
    54. // 路由跳转到name为name的
    55. router.push({ name: name })
    56. }
    57. //watch() 侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
    58. watch(
    59. //监听什么对象(这里监听的是当前路由的路径)
    60. //当路径发生变化时,就执行回调函数
    61. () => route.path,
    62. //新值,老值,回调函数
    63. (newValue, oldValue) => {
    64. //console.log("新值: "+newValue, "老值: "+oldValue)
    65. //监听当路径发生改变时,就执行tabAdd添加Tab标签页的方法
    66. tabAdd(route);
    67. },
    68. //深度监听对象中的所有属性
    69. { deep: true }
    70. )
    71. script>
    1. //定义一个editableTabs数组,里边放初始化元素
    2. editableTabs:[{
    3. title: '主页',
    4. name: 'home',
    5. close: false,
    6. }],
    7. //当前活动标签,默认显示name:'home'的元素
    8. editableTabsValue:"home"

    🎑解释说明

    🎑首页默认初始化显示,不需要移除

    🎑 动态关联菜单项和标签页

     🎑 标签页改变时触发,路由跳转,实现菜单项内容显示

     

    🎑 其他的细节说明都在代码注释中

    🎑 效果图

    🌭实际操作场景一

    🎑 接下来解决一种场景

     🎑就比如

     🎑但是当切换标签页后,会发现之前写的数据销毁了

      🎑那怎么让这样的普通数据保存呢

     🎑 一般的数据信息都是通过KeepAlive进行存储的

     🎑将之前写的改成下边的代码

    1. "{Component}">
    2. <keep-alive>
    3. <component :is="Component" />
    4. keep-alive>

    🌭实际操作场景二

    🎑还有一种场景就是当强制回退路径时,主动打开的标签页还存在

    🎑解决办法就是在初始页面(首页)中通过过滤进行数据初始化

    Home.vue

    1. <script setup lang="ts">
    2. import { onMounted } from 'vue'
    3. import { appStore } from "@/store/appStore";
    4. import { storeToRefs } from "pinia";
    5. let { name, pass, activeTabName, tabList } = storeToRefs(appStore());
    6. const homePage = 'home';
    7. onMounted(() => {
    8. // console.log(activeTabName.value)
    9. if (activeTabName.value == homePage) {
    10. // console.log("执行了")
    11. activeTabName.value = homePage;
    12. //过滤,只留下首页
    13. tabList.value = tabList.value.filter((tab) => tab.name == homePage)
    14. }
    15. })
    16. script>

     🎑这样再执行强制回退就不会出现上面那种情况了

     🎑完事!!!

    💖💖总结说明 

    💦这部分内容有很多细节点,在代码中的注释都有详细解释,在图片中也有大概的一个思路进行分析,最终的目的就是为了将标签页和菜单项完美的进行关联,并且解决上述的两种场景

  • 相关阅读:
    在 Python 中创建 Getter 和 Setter
    洛谷 P8368 [LNOI2022] 串 题解
    基于改进粒子群优化算法的柔性车间调度问题(Python代码实现)
    【python技巧】文本处理-re库字符匹配
    Java设计模式之单例模式详细讲解
    SpringBoot--中间件技术-3:整合mongodb,整合ElasticSearch,附案例含代码(简单易懂)
    深入理解分库、分表、分库分表
    12 张图看懂 CPU 缓存一致性与 MESI 协议,真的一致吗?
    应遵循哪些 GitLab 备份最佳实践
    [含毕业设计论文+PPT+源码等]ssm的房屋交易平台+Java后台管理系统|前后分离VUE
  • 原文地址:https://blog.csdn.net/HeyVIrBbox/article/details/126929702