hldy_app/component/public/specialDrawer.vue

172 lines
3.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>