耀极客论坛

 找回密码
 立即注册
查看: 868|回复: 0

Vue顶部tags浏览历史的实现

[复制链接]

1630

主题

1517

回帖

22万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
229090
发表于 2022-5-8 02:38:40 | 显示全部楼层 |阅读模式
  在管理系统中,常常需要在顶部tags显示浏览历史。本文将教大家如何通过Vue实现这一功能,文中的示例代码讲解详细,需要的可以参考一下

废话
  demo预览



实现的功能
  默认有首页,不能关闭
  点击路由菜单,判断有无存在,没有就添加,有就定位到上面
  点击跳转,点击X可关闭
  关闭当前页,自动跳到下一个tag页面
  如果当前页在最后一个,默认跳到上一个tag页面
  右键菜单,刷新,关闭右侧,关闭所有
  动态判断tags长多,放不下时,出现左右两侧按钮,减少时自动消失
  动态判断窗口放大缩小,自动判断有无左右两侧按钮

正文
  不用任何vuex,乱七八糟的方法,全在一个文件,粘贴即用

  放到你想要的位置即可(此demo,放在了面包屑上面)
  先安装 (监听某dom元素大小的包)
  1. npm install element-resize-detector
复制代码
  tags.vue
  1. ‹template>
  2.   ‹div>
  3.     ‹div class="tags">
  4.       ‹!-- 左箭头 -->
  5.       ‹div
  6.         class="arrow arrow_left"
  7.         v-show="arrowVisible"
  8.         @click="handleClickToLeft"
  9.       >
  10.         ‹i class="el-icon-arrow-left">‹/i>
  11.       ‹/div>
  12.       ‹!-- 标签内容 -->
  13.       ‹div class="tags_content" ref="box">
  14.         ‹span ref="tags">
  15.           ‹el-tag
  16.             v-for="(tag, index) in tags"
  17.             :key="tag.name"
  18.             :class="[active == index ? 'active top_tags' : 'top_tags']"
  19.             effect="dark"
  20.             :closable="tag.name != 'Firstpage1'"
  21.             @close="handleClose(index, tag)"
  22.             @click="clickTag(index, tag)"
  23.             @contextmenu.native.prevent="handleClickContextMenu(index, tag)"
  24.           >
  25.             {{ $t("router." + tag.name) }}
  26.           ‹/el-tag>
  27.         ‹/span>
  28.       ‹/div>
  29.       ‹!-- 右箭头 -->
  30.       ‹div
  31.         class="arrow arrow_right"
  32.         v-show="arrowVisible"
  33.         @click="handleClickToRight"
  34.       >
  35.         ‹i class="el-icon-arrow-right">‹/i>
  36.       ‹/div>
  37.     ‹/div>
  38.     ‹!-- 右键菜单 -->
  39.     ‹ul
  40.       v-show="contextMenu.isShow"
  41.       :style="{ left: contextMenu.menuLeft, top: '96px' }"
  42.       class="el-dropdown-menu el-popper"
  43.       x-placement="bottom-end"
  44.     >
  45.       ‹li
  46.         v-if="this.active == this.contextMenu.index"
  47.         class="el-dropdown-menu__item"
  48.         @click="refresh"
  49.       >
  50.         刷新
  51.       ‹/li>
  52.       ‹li class="el-dropdown-menu__item" @click="closeRightTag">
  53.         关闭右侧
  54.       ‹/li>
  55.       ‹li class="el-dropdown-menu__item" @click="closeOtherTag">
  56.         关闭其它
  57.       ‹/li>
  58.       ‹div x-arrow="" class="popper__arrow">‹/div>
  59.     ‹/ul>
  60.   ‹/div>
  61. ‹/template>
  62. ‹script>
  63. import elementResizeDetectorMaker from "element-resize-detector";
  64. export default {
  65.   data() {
  66.     return {
  67.       // 是否有箭头
  68.       arrowVisible: true,
  69.       // 点击次数
  70.       num: 0,
  71.       active: 0,
  72.       tags: [],
  73.       // 右键的元素
  74.       contextMenu: {
  75.         index: 0,
  76.         tag: {},
  77.         menuLeft: 0,
  78.         isShow: false
  79.       }
  80.     };
  81.   },
  82.   watch: {
  83.     $route() {
  84.       this.getThisPage();
  85.     },
  86.     tags() {
  87.       this.listenFun(this.$refs.tags, "tags");
  88.     }
  89.   },
  90.   mounted() {
  91.     this.listenFun(this.$refs.box, "box");
  92.     var that = this;
  93.     document.addEventListener("click", function(e) {
  94.       that.contextMenu.isShow = false;
  95.     });
  96.   },
  97.   methods: {
  98.     // 监听可视区域宽,浏览器窗口大小改变执行
  99.     listenFun(monitor, dom) {
  100.       let boxWidth = this.$refs.box.offsetWidth,
  101.         tagsWidth = this.$refs.tags.offsetWidth,
  102.         erd = elementResizeDetectorMaker();
  103.       erd.listenTo(monitor, ele => {
  104.         this.$nextTick(() => {
  105.           if (
  106.             (dom == "box" && ele.offsetWidth >= tagsWidth) ||
  107.             (dom == "tags" && ele.offsetWidth ‹= boxWidth)
  108.           ) {
  109.             this.arrowVisible = false;
  110.             this.$refs.box.style.paddingLeft = "16px";
  111.             this.$refs.box.style.paddingRight = "16px";
  112.             this.$refs.box.style.transform = "TranslateX(0px)";
  113.             this.num = 0;
  114.           } else {
  115.             this.arrowVisible = true;
  116.             this.$refs.box.style.paddingLeft = "56px";
  117.             this.$refs.box.style.paddingRight = "56px";
  118.           }
  119.         });
  120.       });
  121.     },
  122.     // 判断当前页
  123.     getThisPage() {
  124.       let currentPgae = this.$route;
  125.       // 判断tags里是否有当前页面
  126.       var index = this.tags.findIndex(tag => tag.name == currentPgae.name);
  127.       if (index == -1) {
  128.         this.tags.push({
  129.           name: currentPgae.name,
  130.           path: currentPgae.path
  131.         });
  132.       }
  133.       // 当前选择页
  134.       this.active = this.tags.findIndex(tag => tag.name == currentPgae.name);
  135.     },
  136.     // 关闭标签
  137.     handleClose(index, tag) {
  138.       this.tags.splice(this.tags.indexOf(tag), 1);
  139.       if (index == this.tags.length) {
  140.         this.active = index - 1;
  141.         this.$router.push(this.tags[index - 1].path);
  142.       } else {
  143.         this.$router.push(this.tags[index].path);
  144.       }
  145.     },
  146.     // 点击标签
  147.     clickTag(index, tag) {
  148.       this.active = index;
  149.       this.$router.push(tag.path);
  150.     },
  151.     // 左侧按钮
  152.     handleClickToLeft() {
  153.       if (this.num > 0) {
  154.         this.num--;
  155.         this.$refs.box.style.transform = `TranslateX(-${this.num * 200}px)`;
  156.       }
  157.     },
  158.     // 右侧按钮
  159.     handleClickToRight() {
  160.       // 最后一个标签右测距离浏览器左侧距离
  161.       let lastChild = document
  162.         .querySelectorAll(".top_tags")
  163.         [this.tags.length - 1].getBoundingClientRect().right;
  164.       // 可视窗口的宽
  165.       let bodyWidth = document.body.offsetWidth;
  166.       // 右侧箭头48+右侧边距16
  167.       if (bodyWidth - lastChild ‹= 64) {
  168.         this.num++;
  169.         this.$refs.box.style.transform = `TranslateX(-${this.num * 200}px)`;
  170.       }
  171.     },
  172.     // 右键
  173.     handleClickContextMenu(index, tag) {
  174.       this.contextMenu.isShow = true;
  175.       this.contextMenu.index = index;
  176.       this.contextMenu.tag = tag;
  177.       let isTag = document
  178.         .querySelectorAll(".top_tags")
  179.         [index].getBoundingClientRect();
  180.       this.contextMenu.menuLeft = isTag.left - 48 + isTag.width / 2 + "px";
  181.     },
  182.     // 刷新
  183.     refresh() {
  184.       this.$router.go(0);
  185.     },
  186.     // 关闭其他
  187.     closeOtherTag() {
  188.       let tagsLin = this.tags.length,
  189.         { index, tag, menuLeft } = this.contextMenu;
  190.       if (index != 0) {
  191.         this.tags = [
  192.           {
  193.             name: "Firstpage1",
  194.             path: "/First/page1"
  195.           },
  196.           {
  197.             name: tag.name,
  198.             path: tag.path
  199.           }
  200.         ];
  201.       } else {
  202.         this.tags = [
  203.           {
  204.             name: "Firstpage1",
  205.             path: "/First/page1"
  206.           }
  207.         ];
  208.       }
  209.       this.active = index;
  210.       this.$router.push(tag.path);
  211.     },
  212.     // 关闭右侧
  213.     closeRightTag() {
  214.       let tagsLin = this.tags.length,
  215.         { index, tag, menuLeft } = this.contextMenu;
  216.       this.tags.splice(index + 1, tagsLin - index);
  217.       this.active = index;
  218.       this.$router.push(tag.path);
  219.     }
  220.   },
  221.   created() {
  222.     // 监听页面刷新
  223.     window.addEventListener("beforeunload", e => {
  224.       localStorage.setItem(
  225.         "tagInfo",
  226.         JSON.stringify({
  227.           active: this.active,
  228.           tags: this.tags
  229.         })
  230.       );
  231.     });
  232.     let tagInfo = localStorage.getItem("tagInfo")
  233.       ? JSON.parse(localStorage.getItem("tagInfo"))
  234.       : {
  235.           active: 0,
  236.           tags: [
  237.             {
  238.               name: "Firstpage1",
  239.               path: "/First/page1"
  240.             }
  241.           ]
  242.         };
  243.     this.active = tagInfo.active;
  244.     this.tags = tagInfo.tags;
  245.   }
  246. };
  247. ‹/script>
  248. ‹style lang="less" scoped>
  249. /deep/.el-tag--dark {
  250.   border-color: transparent;
  251. }
  252. /deep/.el-tag--dark .el-tag__close {
  253.   color: #86909c;
  254.   font-size: 16px;
  255. }
  256. /deep/.el-tag--dark .el-tag__close:hover {
  257.   background: #e7eaf0;
  258. }
  259. .tags {
  260.   position: relative;
  261.   overflow: hidden;
  262.   .arrow {
  263.     width: 48px;
  264.     text-align: center;
  265.     cursor: pointer;
  266.     background: #fff;
  267.     position: absolute;
  268.     z-index: 1;
  269.     &_left {
  270.       left: 0;
  271.       top: 0;
  272.     }
  273.     &_right {
  274.       right: 0;
  275.       top: 0;
  276.     }
  277.   }
  278.   &_content {
  279.     transition: 0.3s;
  280.     white-space: nowrap;
  281.     // padding: 0 16px;
  282.   }
  283.   .top_tags {
  284.     margin-right: 8px;
  285.     cursor: pointer;
  286.     background: #fff;
  287.     font-size: 12px;
  288.     font-weight: 400;
  289.     color: #1d2129;
  290.   }
  291.   .top_tags:hover,
  292.   .active,
  293.   .arrow:hover {
  294.     background: #e7eaf0;
  295.   }
  296. }
  297. ‹/style>
复制代码
重点
  需要修改的地方

  currentPgae.name 是路由结构的name,判断有无存在,没有就添加,有就定位到上面,根据项目修改

  监听刷新时,去本地存储 tags 和 当前页面的active,Ftistpage1 改成自己的首页即可 
  到此这篇关于Vue顶部tags浏览历史的实现的文章就介绍到这了,更多相关Vue顶部tags浏览历史内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|耀极客论坛 ( 粤ICP备2022052845号-2 )|网站地图

GMT+8, 2023-3-24 13:47 , Processed in 0.077738 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表