mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	feat: add tagViews right click menu
This commit is contained in:
		
							parent
							
								
									69d2f82835
								
							
						
					
					
						commit
						a0074411ca
					
				@ -1,15 +1,31 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="tags-view" v-if="!showTags">
 | 
					  <div ref="containerDom" class="tags-view" v-if="!showTags">
 | 
				
			||||||
    <el-scrollbar :vertical="false" class="scroll-container">
 | 
					    <el-scrollbar :vertical="false" class="scroll-container">
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        v-for="(item, index) in dynamicTagList"
 | 
					        v-for="(item, index) in dynamicTagList"
 | 
				
			||||||
        :key="index"
 | 
					        :key="index"
 | 
				
			||||||
        :class="['scroll-item', $route.path === item.path ? 'active' : '']"
 | 
					        :class="['scroll-item', $route.path === item.path ? 'active' : '']"
 | 
				
			||||||
 | 
					        @contextmenu.prevent.native="openMenu(item, $event)"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <router-link :to="item.path">{{ $t(item.meta.title) }}</router-link>
 | 
					        <router-link :to="item.path">{{ $t(item.meta.title) }}</router-link>
 | 
				
			||||||
        <span v-if="index !== 0 " class="el-icon-close" @click="deleteMenu(item)"></span>
 | 
					        <span v-if="index !== 0 " class="el-icon-close" @click="deleteMenu(item)"></span>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </el-scrollbar>
 | 
					    </el-scrollbar>
 | 
				
			||||||
 | 
					    <!-- 右键菜单按钮 -->
 | 
				
			||||||
 | 
					    <ul
 | 
				
			||||||
 | 
					      v-show="visible"
 | 
				
			||||||
 | 
					      :style="{ left: buttonLeft + 'px',top: buttonTop + 'px'}"
 | 
				
			||||||
 | 
					      class="contextmenu"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div v-for="(item,key) in tagsViews" :key="key" style="display:flex; align-items: center;">
 | 
				
			||||||
 | 
					        <li v-if="item.show" @click="selectTag(item,key)">
 | 
				
			||||||
 | 
					          <span>
 | 
				
			||||||
 | 
					            <i :class="item.icon"></i>
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					          {{item.text}}
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </ul>
 | 
				
			||||||
    <!-- 右侧功能按钮 -->
 | 
					    <!-- 右侧功能按钮 -->
 | 
				
			||||||
    <ul class="right-func">
 | 
					    <ul class="right-func">
 | 
				
			||||||
      <li>
 | 
					      <li>
 | 
				
			||||||
@ -43,135 +59,211 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script lang='ts'>
 | 
				
			||||||
import { useDynamicRoutesHook } from "./tagsHook"
 | 
					import { useDynamicRoutesHook } from "./tagsHook";
 | 
				
			||||||
import { useRoute, useRouter } from "vue-router"
 | 
					import { useRoute, useRouter } from "vue-router";
 | 
				
			||||||
import { ref, watchEffect, onBeforeMount, unref, nextTick } from "vue"
 | 
					import { ref, watchEffect, watch, onBeforeMount, unref, nextTick } from "vue";
 | 
				
			||||||
import { storageLocal } from "/@/utils/storage"
 | 
					import { storageLocal } from "/@/utils/storage";
 | 
				
			||||||
import { emitter } from "/@/utils/mitt"
 | 
					import { emitter } from "/@/utils/mitt";
 | 
				
			||||||
import { toggleClass, removeClass } from "/@/utils/operate"
 | 
					import { toggleClass, removeClass } from "/@/utils/operate";
 | 
				
			||||||
import { homeRoute } from "./type"
 | 
					import { templateRef } from "@vueuse/core";
 | 
				
			||||||
let refreshDiv = "refresh-div"
 | 
					import { homeRoute } from "./type";
 | 
				
			||||||
 | 
					let refreshDiv = "refresh-div";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  setup() {
 | 
					  setup() {
 | 
				
			||||||
    const { deleteDynamicTag, dynamicRouteTags, dRoutes, routesLength } = useDynamicRoutesHook()
 | 
					    const {
 | 
				
			||||||
    const route = useRoute()
 | 
					      deleteDynamicTag,
 | 
				
			||||||
    const router = useRouter()
 | 
					      dynamicRouteTags,
 | 
				
			||||||
    const showTags = ref(storageLocal.getItem("tagsVal") || false)
 | 
					      dRoutes,
 | 
				
			||||||
 | 
					      routesLength
 | 
				
			||||||
 | 
					    } = useDynamicRoutesHook();
 | 
				
			||||||
 | 
					    const route = useRoute();
 | 
				
			||||||
 | 
					    const router = useRouter();
 | 
				
			||||||
 | 
					    const showTags = ref(storageLocal.getItem("tagsVal") || false);
 | 
				
			||||||
 | 
					    const containerDom = templateRef<HTMLElement | null>("containerDom", null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const tagsViews = ref([
 | 
					    const tagsViews = ref([
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        icon: "el-icon-refresh-right",
 | 
					        icon: "el-icon-refresh-right",
 | 
				
			||||||
        text: "重新加载",
 | 
					        text: "重新加载",
 | 
				
			||||||
        divided: false,
 | 
					        divided: false,
 | 
				
			||||||
        disabled: false
 | 
					        disabled: false,
 | 
				
			||||||
 | 
					        show: true
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        icon: "el-icon-close",
 | 
					        icon: "el-icon-close",
 | 
				
			||||||
        text: "关闭当前标签页",
 | 
					        text: "关闭当前标签页",
 | 
				
			||||||
        divided: false,
 | 
					        divided: false,
 | 
				
			||||||
        disabled: unref(routesLength) > 1 ? false : true
 | 
					        disabled: unref(routesLength) > 1 ? false : true,
 | 
				
			||||||
 | 
					        show: true
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        icon: "el-icon-more",
 | 
					        icon: "el-icon-more",
 | 
				
			||||||
        text: "关闭其他标签页",
 | 
					        text: "关闭其他标签页",
 | 
				
			||||||
        divided: true,
 | 
					        divided: true,
 | 
				
			||||||
        disabled: unref(routesLength) > 2 ? false : true
 | 
					        disabled: unref(routesLength) > 2 ? false : true,
 | 
				
			||||||
 | 
					        show: true
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        icon: "el-icon-minus",
 | 
					        icon: "el-icon-minus",
 | 
				
			||||||
        text: "关闭全部标签页",
 | 
					        text: "关闭全部标签页",
 | 
				
			||||||
        divided: false,
 | 
					        divided: false,
 | 
				
			||||||
        disabled: unref(routesLength) > 1 ? false : true
 | 
					        disabled: unref(routesLength) > 1 ? false : true,
 | 
				
			||||||
      },
 | 
					        show: true
 | 
				
			||||||
    ])
 | 
					      }
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let visible = ref(false);
 | 
				
			||||||
 | 
					    let buttonLeft = ref(0);
 | 
				
			||||||
 | 
					    let buttonTop = ref(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 当前右键选中的路由信息
 | 
				
			||||||
 | 
					    let currentSelect = ref({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function deleteMenu(item) {
 | 
					    function deleteMenu(item) {
 | 
				
			||||||
      let tagslen = storageLocal.getItem("routesInStorage").length
 | 
					      let tagslen = storageLocal.getItem("routesInStorage").length;
 | 
				
			||||||
      if (tagslen === 2) {
 | 
					      if (tagslen === 2) {
 | 
				
			||||||
        Array.from([1, 2, 3]).forEach(v => {
 | 
					        Array.from([1, 2, 3]).forEach(v => {
 | 
				
			||||||
          tagsViews.value[v].disabled = true
 | 
					          tagsViews.value[v].disabled = true;
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (tagslen === 3) {
 | 
					      if (tagslen === 3) {
 | 
				
			||||||
        tagsViews.value[2].disabled = true
 | 
					        tagsViews.value[2].disabled = true;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      deleteDynamicTag(item, route.path)
 | 
					      deleteDynamicTag(item, route.path);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 初始化页面刷新保证当前路由tabview存在
 | 
					    // 初始化页面刷新保证当前路由tabview存在
 | 
				
			||||||
    let stop = watchEffect(() => {
 | 
					    let stop = watchEffect(() => {
 | 
				
			||||||
      let parentPath = route.path.slice(0, route.path.lastIndexOf("/"))
 | 
					      let parentPath = route.path.slice(0, route.path.lastIndexOf("/"));
 | 
				
			||||||
      dynamicRouteTags(route.path, parentPath)
 | 
					      dynamicRouteTags(route.path, parentPath);
 | 
				
			||||||
    })
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
      // 监听只执行一次,但获取不到当前路由,需要下一个事件轮询中取消监听
 | 
					      // 监听只执行一次,但获取不到当前路由,需要下一个事件轮询中取消监听
 | 
				
			||||||
      stop()
 | 
					      stop();
 | 
				
			||||||
    })
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function onFresh() {
 | 
					    function onFresh() {
 | 
				
			||||||
      toggleClass(true, refreshDiv, document.querySelector(".rotate"))
 | 
					      toggleClass(true, refreshDiv, document.querySelector(".rotate"));
 | 
				
			||||||
      const { path, fullPath } = unref(route)
 | 
					      const { path, fullPath } = unref(route);
 | 
				
			||||||
      router.replace({
 | 
					      router.replace({
 | 
				
			||||||
        path: "/redirect" + fullPath
 | 
					        path: "/redirect" + fullPath
 | 
				
			||||||
      })
 | 
					      });
 | 
				
			||||||
      setTimeout(() => {
 | 
					      setTimeout(() => {
 | 
				
			||||||
        removeClass(document.querySelector(".rotate"), refreshDiv)
 | 
					        removeClass(document.querySelector(".rotate"), refreshDiv);
 | 
				
			||||||
      }, 600)
 | 
					      }, 600);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function onClickDrop(key, item) {
 | 
					    function onClickDrop(key, item, selectRoute) {
 | 
				
			||||||
      if (item.disabled) return
 | 
					      if (item && item.disabled) return;
 | 
				
			||||||
      // 当前路由信息
 | 
					      // 当前路由信息
 | 
				
			||||||
      switch (key) {
 | 
					      switch (key) {
 | 
				
			||||||
        case 0:
 | 
					        case 0:
 | 
				
			||||||
          // 重新加载
 | 
					          // 重新加载
 | 
				
			||||||
          onFresh()
 | 
					          onFresh();
 | 
				
			||||||
          break
 | 
					          break;
 | 
				
			||||||
        case 1:
 | 
					        case 1:
 | 
				
			||||||
          // 关闭当前标签页
 | 
					          // 关闭当前标签页
 | 
				
			||||||
          deleteMenu({ path: route.path, meta: route.meta })
 | 
					          selectRoute
 | 
				
			||||||
          break
 | 
					            ? deleteMenu({ path: selectRoute.path, meta: selectRoute.meta })
 | 
				
			||||||
 | 
					            : deleteMenu({ path: route.path, meta: route.meta });
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
        case 2:
 | 
					        case 2:
 | 
				
			||||||
          // 关闭其他标签页
 | 
					          // 关闭其他标签页
 | 
				
			||||||
          dRoutes.value = [homeRoute, { path: route.path, meta: route.meta }]
 | 
					          dRoutes.value = selectRoute
 | 
				
			||||||
          storageLocal.setItem("routesInStorage", dRoutes.value)
 | 
					            ? [homeRoute, { path: selectRoute.path, meta: selectRoute.meta }]
 | 
				
			||||||
          tagsViews.value[2].disabled = true
 | 
					            : [homeRoute, { path: route.path, meta: route.meta }];
 | 
				
			||||||
          break
 | 
					          storageLocal.setItem("routesInStorage", dRoutes.value);
 | 
				
			||||||
 | 
					          tagsViews.value[2].disabled = true;
 | 
				
			||||||
 | 
					          if (selectRoute) router.push(selectRoute.path);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
        case 3:
 | 
					        case 3:
 | 
				
			||||||
          // 关闭全部标签页
 | 
					          // 关闭全部标签页
 | 
				
			||||||
          dRoutes.value = [homeRoute]
 | 
					          dRoutes.value = [homeRoute];
 | 
				
			||||||
          storageLocal.setItem("routesInStorage", dRoutes.value)
 | 
					          storageLocal.setItem("routesInStorage", dRoutes.value);
 | 
				
			||||||
          router.push("/welcome")
 | 
					          router.push("/welcome");
 | 
				
			||||||
          Array.from([1, 2, 3]).forEach(v => {
 | 
					          Array.from([1, 2, 3]).forEach(v => {
 | 
				
			||||||
            tagsViews.value[v].disabled = true
 | 
					            tagsViews.value[v].disabled = true;
 | 
				
			||||||
          })
 | 
					          });
 | 
				
			||||||
          break
 | 
					          break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onBeforeMount(() => {
 | 
					    function selectTag(item, key) {
 | 
				
			||||||
      emitter.on("tagViewsChange", (key) => {
 | 
					      onClickDrop(key, {}, currentSelect.value);
 | 
				
			||||||
        if (unref(showTags) === key) return
 | 
					    }
 | 
				
			||||||
        showTags.value = key
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      emitter.on("changLayoutRoute", (indexPath) => {
 | 
					    function openMenu(tag, e) {
 | 
				
			||||||
        let currentLen = storageLocal.getItem("routesInStorage").length
 | 
					      if (tag.path === "/welcome") {
 | 
				
			||||||
 | 
					        // 右键菜单为首页,只显示刷新
 | 
				
			||||||
 | 
					        Array.from([1, 2, 3]).forEach(v => {
 | 
				
			||||||
 | 
					          tagsViews.value[v].show = false;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        tagsViews.value[0].show = true;
 | 
				
			||||||
 | 
					      } else if (route.path !== tag.path) {
 | 
				
			||||||
 | 
					        // 右键菜单匹配当前路由,显示刷新
 | 
				
			||||||
 | 
					        tagsViews.value[0].show = false;
 | 
				
			||||||
 | 
					        Array.from([1, 2, 3]).forEach(v => {
 | 
				
			||||||
 | 
					          tagsViews.value[v].show = true;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        Array.from([0, 1, 2, 3]).forEach(v => {
 | 
				
			||||||
 | 
					          tagsViews.value[v].show = true;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      currentSelect.value = tag;
 | 
				
			||||||
 | 
					      const menuMinWidth = 105;
 | 
				
			||||||
 | 
					      const offsetLeft = unref(containerDom).getBoundingClientRect().left;
 | 
				
			||||||
 | 
					      const offsetWidth = unref(containerDom).offsetWidth;
 | 
				
			||||||
 | 
					      const maxLeft = offsetWidth - menuMinWidth;
 | 
				
			||||||
 | 
					      const left = e.clientX - offsetLeft + 15;
 | 
				
			||||||
 | 
					      if (left > maxLeft) {
 | 
				
			||||||
 | 
					        buttonLeft.value = maxLeft;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        buttonLeft.value = left;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      buttonTop.value = e.offsetY * 2;
 | 
				
			||||||
 | 
					      visible.value = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function closeMenu() {
 | 
				
			||||||
 | 
					      visible.value = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    watch(
 | 
				
			||||||
 | 
					      () => visible.value,
 | 
				
			||||||
 | 
					      val => {
 | 
				
			||||||
 | 
					        if (val) {
 | 
				
			||||||
 | 
					          document.body.addEventListener("click", closeMenu);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          document.body.removeEventListener("click", closeMenu);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onBeforeMount(() => {
 | 
				
			||||||
 | 
					      emitter.on("tagViewsChange", key => {
 | 
				
			||||||
 | 
					        if (unref(showTags) === key) return;
 | 
				
			||||||
 | 
					        showTags.value = key;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      emitter.on("changLayoutRoute", indexPath => {
 | 
				
			||||||
 | 
					        let currentLen = storageLocal.getItem("routesInStorage").length;
 | 
				
			||||||
        if (currentLen === 1) {
 | 
					        if (currentLen === 1) {
 | 
				
			||||||
          Array.from([1, 3]).forEach(v => {
 | 
					          Array.from([1, 3]).forEach(v => {
 | 
				
			||||||
            tagsViews.value[v].disabled = false
 | 
					            tagsViews.value[v].disabled = false;
 | 
				
			||||||
          })
 | 
					          });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (currentLen >= 2) {
 | 
					        if (currentLen >= 2) {
 | 
				
			||||||
          Array.from([1, 2, 3]).forEach(v => {
 | 
					          Array.from([1, 2, 3]).forEach(v => {
 | 
				
			||||||
            tagsViews.value[v].disabled = false
 | 
					            tagsViews.value[v].disabled = false;
 | 
				
			||||||
          })
 | 
					          });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      })
 | 
					      });
 | 
				
			||||||
    })
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      dynamicTagList: dRoutes,
 | 
					      dynamicTagList: dRoutes,
 | 
				
			||||||
@ -179,9 +271,16 @@ export default {
 | 
				
			|||||||
      showTags,
 | 
					      showTags,
 | 
				
			||||||
      onFresh,
 | 
					      onFresh,
 | 
				
			||||||
      tagsViews,
 | 
					      tagsViews,
 | 
				
			||||||
      onClickDrop
 | 
					      onClickDrop,
 | 
				
			||||||
    }
 | 
					      visible,
 | 
				
			||||||
  },
 | 
					      buttonLeft,
 | 
				
			||||||
 | 
					      buttonTop,
 | 
				
			||||||
 | 
					      openMenu,
 | 
				
			||||||
 | 
					      closeMenu,
 | 
				
			||||||
 | 
					      selectTag,
 | 
				
			||||||
 | 
					      currentSelect
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -220,6 +319,28 @@ export default {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .contextmenu {
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    background: #fff;
 | 
				
			||||||
 | 
					    z-index: 3000;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    list-style-type: none;
 | 
				
			||||||
 | 
					    padding: 5px 0;
 | 
				
			||||||
 | 
					    border-radius: 4px;
 | 
				
			||||||
 | 
					    font-size: 12px;
 | 
				
			||||||
 | 
					    font-weight: 400;
 | 
				
			||||||
 | 
					    color: #333;
 | 
				
			||||||
 | 
					    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
 | 
				
			||||||
 | 
					    li {
 | 
				
			||||||
 | 
					      margin: 0;
 | 
				
			||||||
 | 
					      padding: 7px 16px;
 | 
				
			||||||
 | 
					      cursor: pointer;
 | 
				
			||||||
 | 
					      &:hover {
 | 
				
			||||||
 | 
					        background: #eee;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.el-icon-close {
 | 
					.el-icon-close {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user