ソースを参照

[Mod 0000]给菜单栏添加鼠标拖动效果(固定在左侧拖动)

wangkeyi 15 時間 前
コミット
0fb334bdc1

+ 65 - 4
src/layouts/default/sider/bottomSideder.vue

@@ -51,13 +51,13 @@
       </div>
     </div>
   </div>
-  <div v-else-if="isShowMenu == 0" class="menu-show-icon">
+  <div v-else-if="isShowMenu == 0" class="menu-show-icon" :style="iconStyle" @mousedown="onDragStart">
     <div class="icon" :class="themeIcon == 'styleTwo' ? 'icon-2' : 'icon-1'" @click="openMenu"></div>
   </div>
 </template>
 
 <script lang="ts">
-  import { defineComponent, nextTick, onMounted, ref, unref } from 'vue';
+  import { computed, defineComponent, onMounted, ref, unref } from 'vue';
   import type { Menu } from '/@/router/types';
   import FourBorderBg from '/@/components/vent/fourBorderBg.vue';
   import { SvgIcon } from '/@/components/Icon';
@@ -89,6 +89,60 @@
       // const themeIcon = appStore.getDarkMode;
       const themeIcon = ref('styleTwo');
 
+      const ICON_SIZE = 60;
+      const iconTop = ref(0);
+      const isDragging = ref(false);
+
+      const iconStyle = computed(() => {
+        if (isDragging.value) {
+          return { left: '5px', top: iconTop.value + 'px', transition: 'none' };
+        }
+        return { left: '5px', top: iconTop.value + 'px', transition: 'top 0.3s ease' };
+      });
+
+      onMounted(() => {
+        iconTop.value = document.documentElement.clientHeight - ICON_SIZE - 5;
+      });
+
+      const DRAG_THRESHOLD = 5;
+
+      function onDragStart(e: MouseEvent) {
+        e.preventDefault();
+        const startY = e.clientY;
+        const startX = e.clientX;
+        const rect = (e.target as HTMLElement).closest('.menu-show-icon')!.getBoundingClientRect();
+        const dragOffsetY = e.clientY - rect.top;
+        let dragged = false;
+
+        const onMove = (ev: MouseEvent) => {
+          ev.preventDefault();
+          if (!dragged && (Math.abs(ev.clientX - startX) > DRAG_THRESHOLD || Math.abs(ev.clientY - startY) > DRAG_THRESHOLD)) {
+            dragged = true;
+            isDragging.value = true;
+            iconTop.value = rect.top;
+          }
+          if (dragged) {
+            const clientH = document.documentElement.clientHeight;
+            iconTop.value = Math.max(0, Math.min(clientH - ICON_SIZE, ev.clientY - dragOffsetY));
+          }
+        };
+
+        const onUp = (ev: MouseEvent) => {
+          if (dragged) {
+            isDragging.value = false;
+            const clientH = document.documentElement.clientHeight;
+            iconTop.value = Math.max(0, Math.min(clientH - ICON_SIZE, iconTop.value));
+            ev.preventDefault();
+            ev.stopPropagation();
+          }
+          document.removeEventListener('mousemove', onMove);
+          document.removeEventListener('mouseup', onUp);
+        };
+
+        document.addEventListener('mousemove', onMove);
+        document.addEventListener('mouseup', onUp);
+      }
+
       function selectMenu(e: Event, programMenu) {
         e.stopPropagation();
         currentParentRoute.value = programMenu;
@@ -164,6 +218,9 @@
         go,
         geHome,
         currentParentRoute,
+        iconStyle,
+        isDragging,
+        onDragStart,
       };
     },
   });
@@ -305,9 +362,13 @@
 
   .menu-show-icon {
     position: fixed;
-    bottom: 5px;
-    left: 5px;
     z-index: 1000000;
+    cursor: grab;
+    user-select: none;
+
+    &:active {
+      cursor: grabbing;
+    }
 
     .icon {
       width: 60px;

+ 60 - 4
src/layouts/default/sider/bottomSideder3.vue

@@ -47,13 +47,13 @@
       </div>
     </SiderBorderBg>
   </div>
-  <div v-else-if="isShowMenu == 0" class="menu-show-icon">
+  <div v-else-if="isShowMenu == 0" class="menu-show-icon" :style="iconStyle" @mousedown="onDragStart">
     <div class="icon" @click="openMenu"></div>
   </div>
 </template>
 
 <script lang="ts">
-  import { defineComponent, nextTick, onMounted, ref, unref } from 'vue';
+  import { computed, defineComponent, onMounted, ref, unref } from 'vue';
   import type { Menu } from '/@/router/types';
   import { SvgIcon } from '/@/components/Icon';
   import { getMenus } from '/@/router/menus';
@@ -83,6 +83,55 @@
       const userStore = useUserStoreWithOut();
       const themeIcon = ref('styleTwo');
 
+      const ICON_SIZE = 60;
+      const DRAG_THRESHOLD = 5;
+      const iconTop = ref(0);
+      const isDragging = ref(false);
+
+      const iconStyle = computed(() => {
+        if (isDragging.value) {
+          return { left: '5px', top: iconTop.value + 'px', transition: 'none' };
+        }
+        return { left: '5px', top: iconTop.value + 'px', transition: 'top 0.3s ease' };
+      });
+
+      function onDragStart(e: MouseEvent) {
+        e.preventDefault();
+        const startY = e.clientY;
+        const startX = e.clientX;
+        const rect = (e.target as HTMLElement).closest('.menu-show-icon')!.getBoundingClientRect();
+        const dragOffsetY = e.clientY - rect.top;
+        let dragged = false;
+
+        const onMove = (ev: MouseEvent) => {
+          ev.preventDefault();
+          if (!dragged && (Math.abs(ev.clientX - startX) > DRAG_THRESHOLD || Math.abs(ev.clientY - startY) > DRAG_THRESHOLD)) {
+            dragged = true;
+            isDragging.value = true;
+            iconTop.value = rect.top;
+          }
+          if (dragged) {
+            const clientH = document.documentElement.clientHeight;
+            iconTop.value = Math.max(0, Math.min(clientH - ICON_SIZE, ev.clientY - dragOffsetY));
+          }
+        };
+
+        const onUp = (ev: MouseEvent) => {
+          if (dragged) {
+            isDragging.value = false;
+            const clientH = document.documentElement.clientHeight;
+            iconTop.value = Math.max(0, Math.min(clientH - ICON_SIZE, iconTop.value));
+            ev.preventDefault();
+            ev.stopPropagation();
+          }
+          document.removeEventListener('mousemove', onMove);
+          document.removeEventListener('mouseup', onUp);
+        };
+
+        document.addEventListener('mousemove', onMove);
+        document.addEventListener('mouseup', onUp);
+      }
+
       function selectMenu(e: Event, programMenu) {
         e.stopPropagation();
         currentParentRoute.value = programMenu;
@@ -133,6 +182,7 @@
       }
 
       onMounted(async () => {
+        iconTop.value = document.documentElement.clientHeight - ICON_SIZE - 5;
         menuModules.value = await getMenus();
         const index = menuModules.value.findIndex((menu) => menu.children && menu.children.length > 0);
         currentParentRoute.value = menuModules.value[index];
@@ -148,6 +198,8 @@
         go,
         geHome,
         currentParentRoute,
+        iconStyle,
+        onDragStart,
       };
     },
   });
@@ -462,9 +514,13 @@
 
   .menu-show-icon {
     position: fixed;
-    bottom: 20px;
-    left: 25px;
     z-index: 1000000;
+    cursor: grab;
+    user-select: none;
+
+    &:active {
+      cursor: grabbing;
+    }
 
     .icon {
       width: 60px;