feat(components): 实现侧边栏拖动功能
- 在 SideButton 组件中添加拖动功能,支持鼠标和触摸操作 -优化 artDetail 页面中的拖动逻辑,限制拖动范围 -修复 liveRoom 组件中的拖动相关问题
This commit is contained in:
parent
aad429be0a
commit
2f8eb36a52
@ -14,7 +14,7 @@ const initData = async () => {
|
||||
detail.value = res.data
|
||||
}
|
||||
}
|
||||
const position = ref({x: window?.innerWidth - 120 || 0, y: 240}) // 设置初始位置在右侧
|
||||
const position = ref({x: window?.innerWidth - 120 || 0, y: 240})
|
||||
const startPosition = ref({x: 0, y: 0})
|
||||
const isDragging = ref(false)
|
||||
|
||||
@ -33,38 +33,30 @@ const onDrag = (e) => {
|
||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
||||
|
||||
// 获取窗口尺寸
|
||||
const maxX = window.innerWidth - 108 // 减去元素宽度
|
||||
const maxY = window.innerHeight - 137 // 减去元素高度
|
||||
const maxX = window.innerWidth - 108
|
||||
const maxY = window.innerHeight - 137
|
||||
|
||||
// 限制范围
|
||||
const x = Math.min(Math.max(0, clientX - startPosition.value.x), maxX)
|
||||
const y = Math.min(Math.max(0, clientY - startPosition.value.y), maxY)
|
||||
|
||||
position.value = {x, y}
|
||||
}
|
||||
}
|
||||
|
||||
const stopDrag = () => {
|
||||
isDragging.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 鼠标事件
|
||||
document.addEventListener('mousemove', onDrag)
|
||||
document.addEventListener('mouseup', stopDrag)
|
||||
// 触摸事件
|
||||
document.addEventListener('touchmove', onDrag)
|
||||
document.addEventListener('touchend', stopDrag)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('mousemove', onDrag)
|
||||
document.removeEventListener('mouseup', stopDrag)
|
||||
document.removeEventListener('touchmove', onDrag)
|
||||
document.removeEventListener('touchend', stopDrag)
|
||||
})
|
||||
|
||||
initData()
|
||||
</script>
|
||||
|
||||
|
@ -1,17 +1,93 @@
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import lockClosed from "@/static/images/lockdfd@2x.png";
|
||||
import lockOpen from "@/static/images/lock4@2x.png";
|
||||
import {liveStore} from "@/stores/live/index.js";
|
||||
import { ref, computed, onMounted, onBeforeUnmount } from "vue"
|
||||
import lockClosed from "@/static/images/lockdfd@2x.png"
|
||||
import lockOpen from "@/static/images/lock4@2x.png"
|
||||
import { liveStore } from "@/stores/live/index.js"
|
||||
import xButton from '@/components/x-button/index.vue'
|
||||
import tangPopup from './tangPopup.vue'
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
import { goodStore } from "@/stores/goods/index.js"
|
||||
import { authStore } from "~/stores/auth/index.js"
|
||||
|
||||
const {quoteStatus, changeStatus, show, auctionData, getSocketData} = liveStore();
|
||||
const {pageRef} = goodStore();
|
||||
const {userInfo} = authStore()
|
||||
const { quoteStatus, changeStatus, show, auctionData, getSocketData } = liveStore()
|
||||
const { pageRef } = goodStore()
|
||||
const { userInfo } = authStore()
|
||||
const showTang = ref(false)
|
||||
|
||||
// 拖动相关状态
|
||||
const isDragging = ref(false)
|
||||
const startY = ref(0)
|
||||
const currentTop = ref(196) // 初始 top 值
|
||||
const sidebarRef = ref(null)
|
||||
|
||||
// 限制拖动范围
|
||||
const minTop = 0 // 最小 top 值
|
||||
const maxTop = window.innerHeight - 180 // 最大 top 值,减去组件高度
|
||||
|
||||
// 开始拖动
|
||||
const handleMouseDown = (e) => {
|
||||
isDragging.value = true
|
||||
startY.value = e.clientY - currentTop.value
|
||||
document.addEventListener('mousemove', handleMouseMove)
|
||||
document.addEventListener('mouseup', handleMouseUp)
|
||||
}
|
||||
|
||||
// 拖动中
|
||||
const handleMouseMove = (e) => {
|
||||
if (!isDragging.value) return
|
||||
|
||||
let newTop = e.clientY - startY.value
|
||||
// 限制范围
|
||||
newTop = Math.max(minTop, Math.min(newTop, maxTop))
|
||||
currentTop.value = newTop
|
||||
|
||||
// 更新位置
|
||||
if (sidebarRef.value) {
|
||||
sidebarRef.value.style.top = `${newTop}px`
|
||||
}
|
||||
}
|
||||
|
||||
// 结束拖动
|
||||
const handleMouseUp = () => {
|
||||
isDragging.value = false
|
||||
document.removeEventListener('mousemove', handleMouseMove)
|
||||
document.removeEventListener('mouseup', handleMouseUp)
|
||||
}
|
||||
|
||||
// 触摸事件处理(移动端支持)
|
||||
const handleTouchStart = (e) => {
|
||||
isDragging.value = true
|
||||
startY.value = e.touches[0].clientY - currentTop.value
|
||||
}
|
||||
|
||||
const handleTouchMove = (e) => {
|
||||
if (!isDragging.value) return
|
||||
|
||||
let newTop = e.touches[0].clientY - startY.value
|
||||
newTop = Math.max(minTop, Math.min(newTop, maxTop))
|
||||
currentTop.value = newTop
|
||||
|
||||
if (sidebarRef.value) {
|
||||
sidebarRef.value.style.top = `${newTop}px`
|
||||
}
|
||||
}
|
||||
|
||||
const handleTouchEnd = () => {
|
||||
isDragging.value = false
|
||||
}
|
||||
|
||||
// 组件挂载时添加事件监听
|
||||
onMounted(() => {
|
||||
if (sidebarRef.value) {
|
||||
sidebarRef.value.style.top = `${currentTop.value}px`
|
||||
}
|
||||
})
|
||||
|
||||
// 组件卸载时清理事件监听
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('mousemove', handleMouseMove)
|
||||
document.removeEventListener('mouseup', handleMouseUp)
|
||||
})
|
||||
|
||||
const openOne = () => {
|
||||
showTang.value = true
|
||||
}
|
||||
@ -24,24 +100,41 @@ const paySide = computed(() => {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
const goPay = () => {
|
||||
show.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-white w-60px rounded-l-4px overflow-hidden">
|
||||
<div
|
||||
ref="sidebarRef"
|
||||
class="bg-white w-60px rounded-l-4px overflow-hidden absolute right-0 z-999 cursor-move"
|
||||
@mousedown="handleMouseDown"
|
||||
@touchstart="handleTouchStart"
|
||||
@touchmove="handleTouchMove"
|
||||
@touchend="handleTouchEnd"
|
||||
>
|
||||
<!-- 拍品信息 -->
|
||||
<van-button class="w-60px !h-60px" @click="openOne" style="border: none;border-radius: 0">
|
||||
<van-button
|
||||
class="w-60px !h-60px"
|
||||
@click="openOne"
|
||||
style="border: none;border-radius: 0"
|
||||
>
|
||||
<div class="text-center flex flex-col justify-center items-center text-#7D7D7F text-12px">
|
||||
<div>{{ $t('live_room.lots') }}</div>
|
||||
<div>({{ auctionData?.artwork?.index }}/{{ pageRef.itemCount ?? 0 }})</div>
|
||||
</div>
|
||||
</van-button>
|
||||
|
||||
<tangPopup v-model:show="showTang"></tangPopup>
|
||||
|
||||
<!-- 出价开关 -->
|
||||
<van-button class="w-60px !h-60px" @click="changeStatus"
|
||||
style="border-right: none;border-left: none;border-radius: 0;padding: 0">
|
||||
<van-button
|
||||
class="w-60px !h-60px"
|
||||
@click="changeStatus"
|
||||
style="border-right: none;border-left: none;border-radius: 0;padding: 0"
|
||||
>
|
||||
<div class="text-center flex flex-col justify-center items-center">
|
||||
<div class="mb-4px">
|
||||
<img
|
||||
@ -50,19 +143,35 @@ const goPay = () => {
|
||||
alt="锁图标"
|
||||
/>
|
||||
</div>
|
||||
<div :class="quoteStatus ? 'text-gray-500' : 'text-blue-600'" class="text-10px transition-colors duration-200">
|
||||
<div
|
||||
:class="quoteStatus ? 'text-gray-500' : 'text-blue-600'"
|
||||
class="text-10px transition-colors duration-200"
|
||||
>
|
||||
{{ quoteStatus ? $t('live_room.colse_bid') : $t('live_room.start_bid') }}
|
||||
</div>
|
||||
</div>
|
||||
</van-button>
|
||||
|
||||
<!-- 支付 -->
|
||||
<van-button v-if="paySide" class="w-60px !h-60px" style="border: none;border-radius: 0" @click="goPay">
|
||||
<van-button
|
||||
v-if="paySide"
|
||||
class="w-60px !h-60px"
|
||||
style="border: none;border-radius: 0"
|
||||
@click="goPay"
|
||||
>
|
||||
<div class="text-center flex flex-col justify-center items-center text-yellow-600">
|
||||
<div class="text-10px">RMB</div>
|
||||
<div class="text-12px">5,000</div>
|
||||
<div class="text-10px">{{ $t('art_detail_page.button') }}</div>
|
||||
</div>
|
||||
</van-button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.cursor-move {
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
touch-action: none;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user