hldy_app/component/public/specialDrawer.vue

208 lines
4.4 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">
<!-- 抽屉中间的半圆 -->
2025-08-29 17:33:30 +08:00
<view class="drawer-content-circle" :class="circletarget?`pulse`:``" :style="isVisible?{}:{background:`linear-gradient(to bottom,#62E8FF,#0097FF)`}" @click="whiteDrawer">
2025-08-13 17:19:40 +08:00
<image class="drawer-img" :src="isVisible?'/static/index/watch/whitearrow.png':'/static/index/watch/arrow.png' " />
</view>
<slot />
</view>
</view>
</view>
</template>
2025-08-29 17:33:30 +08:00
<script setup lang="ts">
2025-08-13 17:19:40 +08:00
import {
ref,
defineProps,
computed,
onMounted
} from 'vue'
// 控制抽屉显示隐藏
const isVisible = ref(false)
2025-08-29 17:33:30 +08:00
// 定义 emit 事件
const emit = defineEmits<{
(e: 'open'): void
}>()
2025-08-13 17:19:40 +08:00
// 接收父组件传入的宽度百分比
const props = defineProps({
widNumber: {
type: Number,
2025-08-21 16:51:53 +08:00
default: 25
2025-08-29 17:33:30 +08:00
},
circletarget:{
type: Boolean,
default: false
2025-08-13 17:19:40 +08:00
}
})
// 获取屏幕宽度,用于拖拽计算
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
2025-08-29 17:33:30 +08:00
emit('open')
2025-08-13 17:19:40 +08:00
}
function closeDrawer() {
isVisible.value = false
}
function whiteDrawer() {
// 点击半圆:切换 & 旋转
2025-08-29 17:33:30 +08:00
if(isVisible.value){
closeDrawer()
}else{
openDrawer()
}
2025-08-13 17:19:40 +08:00
}
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()
}
currentOffset.value = 0
}
</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;
2025-08-21 16:51:53 +08:00
bottom: 240rpx;
2025-08-13 17:19:40 +08:00
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;
2025-08-21 16:51:53 +08:00
// transform: rotate(180deg);
2025-08-13 17:19:40 +08:00
}
2025-08-29 17:33:30 +08:00
.target {
--color: #99C9FD;
--thick: 2px;
--radius: 150rpx;
--outline-offset: 5rpx;
/* 外扩多少 */
/* 内层虚线(你现在用的) */
border-radius: var(--radius);
background-color: #ddf0ff;
/* 内部背景 */
animation: scalePulse 360ms cubic-bezier(.2, .8, .2, 1);
/* 外层虚线:放在 outline不会影响元素尺寸 */
outline: var(--thick) dashed var(--color);
outline-offset: var(--outline-offset);
/* 保证文本 / 子元素在最上层 */
// position: relative;
z-index: 1;
}
.pulse{
/* 可调参数 */
--scale: 1.2;
--dur: 0.8s;
animation: pulse var(--dur) ease-in-out infinite;
transform-origin: center center;
will-change: transform;
}
/* 放大到一定值再回到原始(平滑) */
@keyframes pulse{
0% { transform: scale(1); }
50% { transform: scale(var(--scale)); }
100% { transform: scale(1); }
}
2025-08-13 17:19:40 +08:00
</style>