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
|
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 startPosition = ref({x: 0, y: 0})
|
||||||
const isDragging = ref(false)
|
const isDragging = ref(false)
|
||||||
|
|
||||||
@ -33,38 +33,30 @@ const onDrag = (e) => {
|
|||||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
||||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
||||||
|
|
||||||
// 获取窗口尺寸
|
const maxX = window.innerWidth - 108
|
||||||
const maxX = window.innerWidth - 108 // 减去元素宽度
|
const maxY = window.innerHeight - 137
|
||||||
const maxY = window.innerHeight - 137 // 减去元素高度
|
|
||||||
|
|
||||||
// 限制范围
|
|
||||||
const x = Math.min(Math.max(0, clientX - startPosition.value.x), maxX)
|
const x = Math.min(Math.max(0, clientX - startPosition.value.x), maxX)
|
||||||
const y = Math.min(Math.max(0, clientY - startPosition.value.y), maxY)
|
const y = Math.min(Math.max(0, clientY - startPosition.value.y), maxY)
|
||||||
|
|
||||||
position.value = {x, y}
|
position.value = {x, y}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stopDrag = () => {
|
const stopDrag = () => {
|
||||||
isDragging.value = false
|
isDragging.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 鼠标事件
|
|
||||||
document.addEventListener('mousemove', onDrag)
|
document.addEventListener('mousemove', onDrag)
|
||||||
document.addEventListener('mouseup', stopDrag)
|
document.addEventListener('mouseup', stopDrag)
|
||||||
// 触摸事件
|
|
||||||
document.addEventListener('touchmove', onDrag)
|
document.addEventListener('touchmove', onDrag)
|
||||||
document.addEventListener('touchend', stopDrag)
|
document.addEventListener('touchend', stopDrag)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
document.removeEventListener('mousemove', onDrag)
|
document.removeEventListener('mousemove', onDrag)
|
||||||
document.removeEventListener('mouseup', stopDrag)
|
document.removeEventListener('mouseup', stopDrag)
|
||||||
document.removeEventListener('touchmove', onDrag)
|
document.removeEventListener('touchmove', onDrag)
|
||||||
document.removeEventListener('touchend', stopDrag)
|
document.removeEventListener('touchend', stopDrag)
|
||||||
})
|
})
|
||||||
|
|
||||||
initData()
|
initData()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,17 +1,93 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {ref} from "vue";
|
import { ref, computed, onMounted, onBeforeUnmount } from "vue"
|
||||||
import lockClosed from "@/static/images/lockdfd@2x.png";
|
import lockClosed from "@/static/images/lockdfd@2x.png"
|
||||||
import lockOpen from "@/static/images/lock4@2x.png";
|
import lockOpen from "@/static/images/lock4@2x.png"
|
||||||
import {liveStore} from "@/stores/live/index.js";
|
import { liveStore } from "@/stores/live/index.js"
|
||||||
import xButton from '@/components/x-button/index.vue'
|
import xButton from '@/components/x-button/index.vue'
|
||||||
import tangPopup from './tangPopup.vue'
|
import tangPopup from './tangPopup.vue'
|
||||||
import {goodStore} from "@/stores/goods/index.js";
|
import { goodStore } from "@/stores/goods/index.js"
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
import { authStore } from "~/stores/auth/index.js"
|
||||||
|
|
||||||
const {quoteStatus, changeStatus, show, auctionData, getSocketData} = liveStore();
|
const { quoteStatus, changeStatus, show, auctionData, getSocketData } = liveStore()
|
||||||
const {pageRef} = goodStore();
|
const { pageRef } = goodStore()
|
||||||
const {userInfo} = authStore()
|
const { userInfo } = authStore()
|
||||||
const showTang = ref(false)
|
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 = () => {
|
const openOne = () => {
|
||||||
showTang.value = true
|
showTang.value = true
|
||||||
}
|
}
|
||||||
@ -24,25 +100,42 @@ const paySide = computed(() => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const goPay = () => {
|
const goPay = () => {
|
||||||
show.value = true
|
show.value = true
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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 class="text-center flex flex-col justify-center items-center text-#7D7D7F text-12px">
|
||||||
<div>{{ $t('live_room.lots') }}</div>
|
<div>{{ $t('live_room.lots') }}</div>
|
||||||
<div>({{ auctionData?.artwork?.index }}/{{ pageRef.itemCount ?? 0 }})</div>
|
<div>({{ auctionData?.artwork?.index }}/{{ pageRef.itemCount ?? 0 }})</div>
|
||||||
</div>
|
</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
|
|
||||||
<tangPopup v-model:show="showTang"></tangPopup>
|
<tangPopup v-model:show="showTang"></tangPopup>
|
||||||
|
|
||||||
<!-- 出价开关 -->
|
<!-- 出价开关 -->
|
||||||
<van-button class="w-60px !h-60px" @click="changeStatus"
|
<van-button
|
||||||
style="border-right: none;border-left: none;border-radius: 0;padding: 0">
|
class="w-60px !h-60px"
|
||||||
<div class="text-center flex flex-col justify-center items-center">
|
@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">
|
<div class="mb-4px">
|
||||||
<img
|
<img
|
||||||
:src="quoteStatus ? lockClosed : lockOpen"
|
:src="quoteStatus ? lockClosed : lockOpen"
|
||||||
@ -50,19 +143,35 @@ const goPay = () => {
|
|||||||
alt="锁图标"
|
alt="锁图标"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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') }}
|
{{ quoteStatus ? $t('live_room.colse_bid') : $t('live_room.start_bid') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
|
|
||||||
<!-- 支付 -->
|
<!-- 支付 -->
|
||||||
<van-button v-if="paySide" class="w-60px !h-60px" style="border: none;border-radius: 0" @click="goPay">
|
<van-button
|
||||||
<div class="text-center flex flex-col justify-center items-center text-yellow-600">
|
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-10px">RMB</div>
|
||||||
<div class="text-12px">5,000</div>
|
<div class="text-12px">5,000</div>
|
||||||
<div class="text-10px">{{ $t('art_detail_page.button') }}</div>
|
<div class="text-10px">{{ $t('art_detail_page.button') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cursor-move {
|
||||||
|
cursor: move;
|
||||||
|
user-select: none;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user