hldy_app/component/public/specialDrawer.vue

172 lines
3.5 KiB
Vue
Raw Normal View History

2025-08-13 17:19:40 +08:00
<template>
<view>
<view :class="['drawer', { 'drawer-open': isVisible }]" :style="drawerStyle">
<view class="drawer-content" @touchstart.passive="onTouchStart" @touchmove.passive="onTouchMove"
@touchend="onTouchEnd" @touchcancel="onTouchEnd">
<!-- 抽屉中间的半圆 -->
<view class="drawer-content-circle" :style="isVisible?{}:{background:`linear-gradient(to bottom,#62E8FF,#0097FF)`}" @click="whiteDrawer">
<image class="drawer-img" :src="isVisible?'/static/index/watch/whitearrow.png':'/static/index/watch/arrow.png' " />
</view>
<slot />
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
defineProps,
computed,
onMounted
} from 'vue'
// 控制抽屉显示隐藏
const isVisible = ref(false)
// 接收父组件传入的宽度百分比
const props = defineProps({
widNumber: {
type: Number,
default: 26
}
})
// 获取屏幕宽度,用于拖拽计算
const screenWidth = ref(0)
onMounted(() => {
const sys = uni.getSystemInfoSync()
screenWidth.value = sys.screenWidth
})
// 拖拽状态
const startX = ref(0)
const dragging = ref(false)
const currentOffset = ref(0)
// 计算样式:宽度 + 拖拽或开关 transform
const drawerStyle = computed(() => {
const widthPct = `${props.widNumber}%`
if (dragging.value) {
// 拖动时X 方向正值向右移动抽屉
const offset = currentOffset.value
return {
width: widthPct,
transform: `translateX(${offset}px)`,
transition: 'none'
}
} else {
// 非拖动交由 class 控制开关状态
return {
width: widthPct
}
}
})
// 打开/关闭
function openDrawer() {
isVisible.value = true
}
function closeDrawer() {
isVisible.value = false
}
function whiteDrawer() {
// 点击半圆:切换 & 旋转
isVisible.value = !isVisible.value
rotate180()
}
defineExpose({
openDrawer,
closeDrawer
})
// 拖拽事件
function onTouchStart(e) {
if (!isVisible.value) return
dragging.value = true
currentOffset.value = 0
startX.value = e.touches[0].pageX
}
function onTouchMove(e) {
if (!dragging.value) return
const delta = e.touches[0].pageX - startX.value
currentOffset.value = delta > 0 ? delta : 0
}
function onTouchEnd() {
if (!dragging.value) return
dragging.value = false
const halfPx = screenWidth.value * (props.widNumber / 100) / 2
if (currentOffset.value > halfPx) {
closeDrawer()
rotate180()
}
currentOffset.value = 0
}
// 半圆旋转
const angle = ref(0)
const boxStyle = computed(() => ({
transform: `rotate(${angle.value}deg)`,
transition: 'transform 0.6s ease'
}))
function rotate180() {
angle.value += 180
}
</script>
<style lang="less" scoped>
.drawer {
position: fixed;
bottom: 0;
right: 0;
height: 85vh;
background: #eff0f4;
z-index: 1000;
border-top-left-radius: 80rpx;
border-bottom-left-radius: 80rpx;
/* 初始隐藏 */
transform: translateX(100%);
transition: transform 0.4s ease;
}
.drawer-open {
transform: translateX(0);
}
.drawer-content {
position: relative;
width: 100%;
height: 100%;
}
.drawer-content-circle {
position: absolute;
bottom: 270rpx;
left: -60rpx;
width: 150rpx;
height: 160rpx;
border-radius: 50%;
z-index: -1;
// background: #fff;
background: linear-gradient(to right,
#fff 0rpx,
#eff0f4 60rpx,
#eff0f4 100%);
display: flex;
align-items: center;
clip-path: inset(0 60% 0 0);
}
.drawer-img {
width: 20rpx;
height: 20rpx;
margin-left: 25rpx;
transform: rotate(180deg);
}
</style>