Skip to content

Hooks

@erp/common 提供的 Vue 组合式函数,用于在组件中复用逻辑。

功能概览

  • popupManager - 弹出层 z-index 管理
  • usePopupManager - 弹出层管理 Hook
  • useDraggable - 元素拖拽功能
  • useFormItem - 表单项上下文
  • useLocale / useI18n - 国际化支持

引入方式

typescript
import { 
  popupManager,
  useDraggable 
} from '@erp/common'

popupManager

弹出层层级管理器,用于管理弹窗、下拉框等弹出层的 z-index。

基础用法

typescript
import { popupManager } from '@erp/common'

// 获取下一个 z-index
const zIndex = popupManager.getNextZIndex('popup')

// 添加弹出层并获取 z-index
const zIndex = popupManager.add('popup')

// 移除弹出层
popupManager.delete(zIndex, 'popup')

// 获取当前最高 z-index
const current = popupManager.getCurrentZIndex('popup')

弹出层类型

typescript
type PopupType = 'popup' | 'dialog' | 'message' | 'table'
类型说明基础 z-index
popup普通弹出层(下拉框、提示等)3000
dialog对话框、抽屉3000
message消息提示5000
table表格相关弹出层3000

API

typescript
class PopupManager {
  /** 获取下一个可用的 z-index */
  getNextZIndex(type: PopupType): number
  
  /** 获取当前最高的 z-index */
  getCurrentZIndex(type: PopupType): number
  
  /** 添加弹出层,返回分配的 z-index */
  add(type: PopupType): number
  
  /** 移除弹出层 */
  delete(zIndex: number, type: PopupType): void
  
  /** 判断是否为最后一个对话框 */
  isLastDialog(zIndex: number): boolean
}

在组件中使用

typescript
import { popupManager } from '@erp/common'
import { ref, onMounted, onBeforeUnmount } from 'vue'

const zIndex = ref(0)

onMounted(() => {
  zIndex.value = popupManager.add('popup')
})

onBeforeUnmount(() => {
  popupManager.delete(zIndex.value, 'popup')
})

usePopupManager

弹出层管理 Hook,自动处理 z-index 的分配和回收。

基础用法

typescript
import usePopupManager from '@erp/common'

// 基础用法
const { zIndex, open, close, isLastDialog } = usePopupManager('dialog')

// 响应式 visible
const visible = ref(false)
const { zIndex } = usePopupManager('dialog', { visible })

// 挂载时自动打开
const { zIndex } = usePopupManager('popup', { runOnMounted: true })

参数说明

typescript
function usePopupManager(
  type: PopupType,
  options?: {
    /** 响应式的可见状态,变化时自动管理 z-index */
    visible?: Ref<boolean>
    /** 是否在挂载时自动打开 */
    runOnMounted?: boolean
  }
): {
  /** 当前 z-index(只读) */
  zIndex: Readonly<Ref<number>>
  /** 打开弹出层 */
  open: () => void
  /** 关闭弹出层 */
  close: () => void
  /** 是否为最后一个对话框 */
  isLastDialog: () => boolean
}

使用示例

vue
<template>
  <div class="modal" :style="{ zIndex }">
    <slot />
  </div>
</template>

<script setup>
import usePopupManager from '@erp/common'

const props = defineProps({
  visible: Boolean
})

const { zIndex } = usePopupManager('dialog', {
  visible: toRef(props, 'visible')
})
</script>

useDraggable

拖拽功能 Hook,用于实现元素拖拽。

基础用法

typescript
import { useDraggable } from '@erp/common'
import { ref } from 'vue'

const modalRef = ref<HTMLElement>()
const headerRef = ref<HTMLElement>()

const { position, isDragging } = useDraggable(modalRef, {
  handle: headerRef
})

参数说明

typescript
function useDraggable(
  target: Ref<HTMLElement | undefined>,
  options?: {
    /** 拖拽手柄元素 */
    handle?: Ref<HTMLElement | undefined>
    /** 初始位置 */
    initialValue?: { x: number; y: number }
    /** 是否阻止默认事件 */
    preventDefault?: boolean
    /** 是否阻止冒泡 */
    stopPropagation?: boolean
    /** 拖拽开始回调 */
    onStart?: (position: Position, event: PointerEvent) => void
    /** 拖拽中回调 */
    onMove?: (position: Position, event: PointerEvent) => void
    /** 拖拽结束回调 */
    onEnd?: (position: Position, event: PointerEvent) => void
  }
): {
  /** 当前位置 */
  position: Ref<{ x: number; y: number }>
  /** 是否正在拖拽 */
  isDragging: Ref<boolean>
  /** 样式对象 */
  style: ComputedRef<CSSProperties>
}

使用示例

可拖拽弹窗

vue
<template>
  <div ref="modalRef" class="modal" :style="style">
    <div ref="headerRef" class="modal-header">
      拖拽这里移动
    </div>
    <div class="modal-body">
      <slot />
    </div>
  </div>
</template>

<script setup>
import { useDraggable } from '@erp/common'
import { ref } from 'vue'

const modalRef = ref()
const headerRef = ref()

const { style, isDragging } = useDraggable(modalRef, {
  handle: headerRef,
  onEnd: (pos) => {
    console.log('拖拽结束,位置:', pos)
  }
})
</script>

<style scoped>
.modal-header {
  cursor: move;
}
</style>

限制拖拽范围

typescript
const { position } = useDraggable(elementRef, {
  onMove: (pos) => {
    // 限制在视口内
    pos.x = Math.max(0, Math.min(pos.x, window.innerWidth - 200))
    pos.y = Math.max(0, Math.min(pos.y, window.innerHeight - 100))
  }
})

useFormItem

表单项 Hook,用于在自定义表单组件中获取表单上下文。

基础用法

typescript
import { useFormItem } from '@erp/common'

const { 
  formItemCtx,
  mergedDisabled,
  mergedSize,
  eventHandlers 
} = useFormItem({
  size: props.size,
  disabled: props.disabled
})

返回值

typescript
interface UseFormItemReturn {
  /** 表单项上下文 */
  formItemCtx: FormItemContext | undefined
  
  /** 合并后的禁用状态(组件 > 表单项 > 表单) */
  mergedDisabled: ComputedRef<boolean>
  
  /** 合并后的尺寸(组件 > 表单项 > 表单) */
  mergedSize: ComputedRef<Size>
  
  /** 事件处理器 */
  eventHandlers: {
    onChange: () => void
    onBlur: () => void
  }
}

使用示例

vue
<template>
  <input 
    :disabled="mergedDisabled"
    :class="[`input-${mergedSize}`]"
    @change="eventHandlers.onChange"
    @blur="eventHandlers.onBlur"
  />
</template>

<script setup>
import { useFormItem } from '@erp/common'

const props = defineProps({
  size: String,
  disabled: Boolean
})

const { mergedDisabled, mergedSize, eventHandlers } = useFormItem({
  size: props.size,
  disabled: props.disabled
})
</script>

useLocale / useI18n

国际化 Hook。

基础用法

typescript
import { useLocale, useI18n } from '@erp/common'

// 获取当前语言
const { locale, setLocale } = useLocale()

// 获取翻译函数
const { t } = useI18n()

// 使用翻译
const message = t('common.confirm') // 确认

API

typescript
// useLocale
function useLocale(): {
  locale: Ref<string>
  setLocale: (locale: string) => void
}

// useI18n
function useI18n(): {
  t: (key: string, ...args: any[]) => string
  locale: Ref<string>
}

使用示例

vue
<template>
  <button>{{ t('common.submit') }}</button>
  <span>当前语言: {{ locale }}</span>
</template>

<script setup>
import { useI18n } from '@erp/common'

const { t, locale } = useI18n()
</script>

基于 MIT 许可发布