diff --git a/src/common/hooks/useResizeHandle.ts b/src/common/hooks/useResizeHandle.ts new file mode 100644 index 0000000..3dea0d9 --- /dev/null +++ b/src/common/hooks/useResizeHandle.ts @@ -0,0 +1,71 @@ +import { type Ref, onUnmounted } from 'vue' + +/** + * 拖拽调整宽度 Hook 的参数 + */ +interface UseResizeHandleOptions { + /** 当前宽度响应式引用 */ + width: Ref + /** 宽度变更回调,传入新宽度 */ + onWidthChange: (width: number) => void +} + +/** + * 将侧边栏拖拽调整宽度的逻辑封装为可复用的 composable + * + * 在 mousedown 时绑定 document 级 mousemove/mouseup 监听, + * 拖拽过程中通过 onWidthChange 回调通知外部更新宽度(由外部负责约束范围), + * 拖拽结束后自动清理事件监听和全局样式。 + * + * @param options - 配置项,包含宽度 ref 和变更回调 + * @returns 返回 mousedown 事件处理器,绑定到拖拽手柄元素 + */ +export function useResizeHandle(options: UseResizeHandleOptions): { + onMouseDown: (event: MouseEvent) => void +} { + const { onWidthChange } = options + + /** 是否正在拖拽 */ + let isResizing = false + + /** + * 处理 mousemove,计算新宽度并通知外部 + */ + const onMouseMove = (event: MouseEvent): void => { + if (!isResizing) return + onWidthChange(event.clientX) + } + + /** + * 处理 mouseup,结束拖拽并清理 + */ + const onMouseUp = (): void => { + isResizing = false + document.removeEventListener('mousemove', onMouseMove) + document.removeEventListener('mouseup', onMouseUp) + document.body.style.userSelect = '' + document.body.style.cursor = '' + } + + /** + * 处理 mousedown,开始拖拽 + */ + const onMouseDown = (event: MouseEvent): void => { + event.preventDefault() + isResizing = true + document.addEventListener('mousemove', onMouseMove) + document.addEventListener('mouseup', onMouseUp) + document.body.style.userSelect = 'none' + document.body.style.cursor = 'ew-resize' + } + + /** 组件卸载时兜底清理 */ + onUnmounted(() => { + document.removeEventListener('mousemove', onMouseMove) + document.removeEventListener('mouseup', onMouseUp) + document.body.style.userSelect = '' + document.body.style.cursor = '' + }) + + return { onMouseDown } +} diff --git a/src/layouts/BaseLayout.vue b/src/layouts/BaseLayout.vue index 28d729e..8f0110d 100644 --- a/src/layouts/BaseLayout.vue +++ b/src/layouts/BaseLayout.vue @@ -11,7 +11,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
@@ -40,9 +40,16 @@ import GameList from '@/components/baseLayouts/GameList.vue' import Lobby from '@/components/baseLayouts/Lobby.vue' import { useBaseLayoutStore } from '@/stores' import { storeToRefs } from 'pinia' +import { useResizeHandle } from '@/common/hooks/useResizeHandle' const baseLayoutStore = useBaseLayoutStore() -const { activeGameIcon, activeGameName } = storeToRefs(baseLayoutStore) +const { activeGameIcon, activeGameName, sidebarWidth } = storeToRefs(baseLayoutStore) + +/** 拖拽手柄事件处理器 */ +const { onMouseDown: onResizeMouseDown } = useResizeHandle({ + width: sidebarWidth, + onWidthChange: (width) => baseLayoutStore.setSidebarWidth(width) +})