liveh5-nuxt/app/components/drag-window/index.vue
xingyy 226057ce8f feat(i18n): 优化国际化文案并添加通用拍卖术语- 更新了多个组件中的国际化文案,使其更加统一和准确
- 在 zh-CN.json 中添加了"common"字段,用于存储通用拍卖术语
- 调整了部分组件的布局和样式,以更好地展示国际化文案
2025-02-12 16:50:52 +08:00

199 lines
4.5 KiB
Vue

<script setup>
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
const props = defineProps({
initialPosition: {
type: Object,
default: () => ({ x: 0, y: 0 })
},
stick: {
type: String,
default: null,
validator: (value) => ['left', 'right', 'top', 'bottom', null].includes(value)
},
dragMode: {
type: String,
default: 'free',
validator: (value) => ['free', 'horizontal', 'vertical'].includes(value)
},
stickyDistance: {
type: Number,
default: 20
},
margin: {
type: Number,
default: 0
},
draggable: {
type: Boolean,
default: true
},
zIndex: {
type: Number,
default: 1000
}
})
const emit = defineEmits(['update:position'])
const containerRef = ref(null)
const position = ref(props.initialPosition)
const isDragging = ref(false)
const startPos = ref({ x: 0, y: 0 })
const windowSize = ref({ width: 0, height: 0 })
const elementSize = ref({ width: 0, height: 0 })
const transformStyle = computed(() => ({
transform: `translate3d(${position.value.x}px, ${position.value.y}px, 0)`,
zIndex: props.zIndex,
position: 'fixed',
top: '0',
left: '0', // 添加基准定位点
right: 'auto',
bottom: 'auto'
}))
const updateSizes = () => {
if (typeof window !== 'undefined') {
windowSize.value = {
width: window.innerWidth,
height: window.innerHeight
}
if (containerRef.value) {
elementSize.value = {
width: containerRef.value.offsetWidth,
height: containerRef.value.offsetHeight
}
}
}
}
const handleStick = (pos) => {
if (!props.stick) return pos
const { width, height } = elementSize.value
const { stickyDistance, margin } = props
const maxX = windowSize.value.width - width - margin
const maxY = windowSize.value.height - height - margin
const newPos = { ...pos }
switch (props.stick) {
case 'left':
if (pos.x < stickyDistance) newPos.x = margin
break
case 'right':
if (maxX - pos.x < stickyDistance) newPos.x = maxX
break
case 'top':
if (pos.y < stickyDistance) newPos.y = margin
break
case 'bottom':
if (maxY - pos.y < stickyDistance) newPos.y = maxY
break
}
return newPos
}
const constrainPosition = (pos) => {
const { width, height } = elementSize.value
const { margin } = props
const maxX = windowSize.value.width - width - margin
const maxY = windowSize.value.height - height - margin
return {
x: Math.min(Math.max(pos.x, margin), maxX),
y: Math.min(Math.max(pos.y, margin), maxY)
}
}
const handleStart = (event) => {
if (!props.draggable) return
const e = event.touches ? event.touches[0] : event
isDragging.value = true
startPos.value = {
x: e.clientX - position.value.x,
y: e.clientY - position.value.y
}
}
const handleMove = (event) => {
if (!isDragging.value) return
const e = event.touches ? event.touches[0] : event
let newPos = {
x: e.clientX - startPos.value.x,
y: e.clientY - startPos.value.y
}
if (props.dragMode === 'horizontal') {
newPos.y = position.value.y
} else if (props.dragMode === 'vertical') {
newPos.x = position.value.x
}
newPos = handleStick(newPos)
newPos = constrainPosition(newPos)
position.value = newPos
emit('update:position', newPos)
event.preventDefault()
}
const handleEnd = () => {
isDragging.value = false
}
onMounted(() => {
updateSizes()
window.addEventListener('resize', updateSizes)
document.addEventListener('mousemove', handleMove)
document.addEventListener('mouseup', handleEnd)
document.addEventListener('touchmove', handleMove, { passive: false })
document.addEventListener('touchend', handleEnd)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', updateSizes)
document.removeEventListener('mousemove', handleMove)
document.removeEventListener('mouseup', handleEnd)
document.removeEventListener('touchmove', handleMove)
document.removeEventListener('touchend', handleEnd)
})
watch(() => props.initialPosition, (newPos) => {
position.value = newPos
}, {deep: true})
</script>
<template>
<div
ref="containerRef"
class="drag-window"
:class="{ 'dragging': isDragging }"
:style="transformStyle"
@mousedown="handleStart"
@touchstart="handleStart"
>
<slot></slot>
</div>
</template>
<style scoped>
.drag-window {
position: fixed;
touch-action: none;
user-select: none;
-webkit-user-select: none;
will-change: transform;
transition: transform 0.2s ease;
}
.drag-window.dragging {
transition: none;
cursor: move;
}
</style>