MenuTag.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <template>
  2. <el-card class="box-card">
  3. <div class="tags" ref="tags" :style="{ padding: '6px 10px' }">
  4. <div class="tags-out-box" ref="outBox">
  5. <div
  6. class="tags-box"
  7. ref="box"
  8. :style="{
  9. 'padding-left': '0',
  10. left: `${left}px`,
  11. }"
  12. >
  13. <el-tag
  14. ref="tag"
  15. size="small"
  16. v-for="(tag, i) in tags"
  17. :data-index="i"
  18. :data-id="tag.name"
  19. :key="tag.name"
  20. :closable="tag.name !== 'home' && tag.name !== '驾驶舱'"
  21. :effect="$route.name === tag.name ? 'dark' : 'plain'"
  22. class="tagBox"
  23. :class="{
  24. 'unselected-tag': $route.name !== tag.name,
  25. 'selected-tag':
  26. $route.name === tag.name ||
  27. (tag.name === 'home' && $route.name === '驾驶舱'),
  28. }"
  29. @contextmenu.native.prevent="handleClickContextMenu($event, tag, i)"
  30. @click="handleTagClick($event, tag)"
  31. @close="handleTagClose(tag, i)"
  32. >
  33. {{ tag.label }}
  34. </el-tag>
  35. </div>
  36. </div>
  37. <ul
  38. class="right-menu"
  39. :style="{ left: menuLeft, top: menuTop, zIndex: 99 }"
  40. v-show="contextMenuVisible"
  41. >
  42. <a href="javascript:;" @click="refresh">刷新</a>
  43. <a href="javascript:;" @click="closeAllTag">关闭所有</a>
  44. </ul>
  45. </div>
  46. </el-card>
  47. </template>
  48. <script>
  49. import { mapState, mapActions } from "vuex";
  50. export default {
  51. data() {
  52. return {
  53. contextMenuVisible: false, // 是否显示菜单
  54. menuLeft: "", // 右键菜单距离浏览器左边的距离
  55. menuTop: "", // 右键菜单距离浏览器上边的距离
  56. tagIndex: 0, // 当前点击的tag的索引
  57. tag: {}, // 当前右键点击的tag对象
  58. arrowVisible: false, // 是否显示箭头
  59. tagsBoxWidth: 0, // ref 为 outBox 的长度
  60. tagsWidth: 0, // ref 为 tags 的长度
  61. left: 0, // ref 为 box 节点相对于左边的距离,用于箭头点击
  62. };
  63. },
  64. computed: {
  65. ...mapState({
  66. tags: (state) => state.menuTag.tagList,
  67. }),
  68. },
  69. methods: {
  70. ...mapActions("menuTag", [
  71. "addTag",
  72. "removeTag",
  73. "removeOtherTags",
  74. "removeAllTags",
  75. "setTagList",
  76. ]),
  77. handleClickContextMenu(event, tag, index) {
  78. this.contextMenuVisible = true;
  79. this.menuLeft = `${event.clientX}px`;
  80. this.menuTop = `${event.clientY}px`;
  81. this.tagIndex = index;
  82. this.tag = tag;
  83. },
  84. handleTagClick(event, tag) {
  85. this.contextMenuVisible = false;
  86. // 点击标签时的处理逻辑
  87. // 例如:导航到标签对应的页面
  88. this.$router.push(tag.path);
  89. },
  90. handleTagClose(tag, index) {
  91. // 关闭标签时的处理逻辑
  92. if (tag.name !== "home") {
  93. this.removeTag(tag);
  94. }
  95. },
  96. refresh() {
  97. // 刷新标签页的逻辑
  98. this.$router.push({ path: this.tag.path, query: { refresh: true } });
  99. this.contextMenuVisible = false;
  100. },
  101. closeAllTag() {
  102. // 关闭所有标签的逻辑
  103. this.removeAllTags();
  104. this.contextMenuVisible = false;
  105. },
  106. updateArrowVisibility() {
  107. this.tagsBoxWidth = this.$refs.outBox.offsetWidth;
  108. this.tagsWidth = this.$refs.box.scrollWidth;
  109. // this.arrowVisible = this.tagsWidth > this.tagsBoxWidth;
  110. },
  111. },
  112. watch: {
  113. tags() {
  114. this.$nextTick(() => {
  115. this.updateArrowVisibility();
  116. });
  117. },
  118. },
  119. mounted() {
  120. this.updateArrowVisibility();
  121. window.addEventListener("resize", this.updateArrowVisibility);
  122. },
  123. beforeDestroy() {
  124. window.removeEventListener("resize", this.updateArrowVisibility);
  125. },
  126. };
  127. </script>
  128. <style lang="scss" scoped>
  129. ::v-deep.box-card {
  130. border: 0 !important;
  131. border-bottom: 1px solid #d8dce5 !important;
  132. -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12),
  133. 0 0 3px 0 rgba(0, 0, 0, 0.04) !important;
  134. box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04) !important;
  135. .tags-out-box {
  136. width: 100%;
  137. .tags-box {
  138. width: 100%;
  139. overflow-x: scroll;
  140. }
  141. .tags-box::-webkit-scrollbar {
  142. width: 0px;
  143. height: 0px;
  144. background: transparent; /* 隐藏滚动条 */
  145. }
  146. .tags-box {
  147. scrollbar-width: none; /* 隐藏滚动条 */
  148. -ms-overflow-style: none; /* 隐藏滚动条(旧版 Internet Explorer 和 Edge) */
  149. }
  150. .tags-box::-webkit-scrollbar {
  151. width: 0px;
  152. height: 0px;
  153. background: transparent; /* 隐藏滚动条 */
  154. }
  155. .tags-box {
  156. overflow: -moz-scrollbars-none; /* 隐藏滚动条(旧版 Firefox) */
  157. -ms-overflow-style: none; /* 隐藏滚动条(旧版 Internet Explorer 和 Edge) */
  158. scrollbar-width: none; /* 隐藏滚动条(Firefox) */
  159. }
  160. .tags-box::-webkit-scrollbar {
  161. width: 0px;
  162. height: 0px;
  163. background: transparent; /* 隐藏滚动条(Webkit 浏览器) */
  164. }
  165. }
  166. }
  167. ::v-deep.box-card .el-card__body {
  168. padding: 0 !important;
  169. }
  170. .tagBox {
  171. cursor: pointer;
  172. }
  173. .tags {
  174. width: 100%;
  175. white-space: nowrap;
  176. background-color: #fff;
  177. // padding: 12px 10px;
  178. &-out-box {
  179. display: inline-block;
  180. position: relative;
  181. }
  182. &-box {
  183. position: relative;
  184. transition: 0.3s;
  185. }
  186. }
  187. .el-tag {
  188. margin: 0 5px;
  189. // &.selected-tag {
  190. // background-color: #409eff !important; // 选中的背景色
  191. // color: #fff; // 选中的文字颜色
  192. // }
  193. &.unselected-tag {
  194. background-color: #fff !important; // 未选中的背景色
  195. color: #333 !important; // 未选中的文字颜色
  196. border-color: #ccc !important;
  197. }
  198. }
  199. .right-menu {
  200. position: absolute;
  201. background-color: #fff;
  202. border: 1px solid #dcdcdc;
  203. list-style: none;
  204. padding: 10px 0;
  205. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  206. a {
  207. display: block;
  208. padding: 5px 20px;
  209. color: #666;
  210. text-decoration: none;
  211. &:hover {
  212. background-color: #f5f5f5;
  213. }
  214. }
  215. }
  216. </style>