|
|
@@ -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;
|