173 lines
3.7 KiB
Vue
173 lines
3.7 KiB
Vue
<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)`}:{background:`linear-gradient(to bottom,#62E8FF,#0097FF)`}" @click="whiteDrawer">
|
||
<image class="drawer-img" :style="{transform:isVisible?`rotate(180deg)`:``}" :src="isVisible?'/static/index/watch/arrow.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: 17
|
||
}
|
||
})
|
||
|
||
// 获取屏幕宽度,用于拖拽计算
|
||
const screenWidth = ref(0)
|
||
onMounted(() => {
|
||
const sys = uni.getSystemInfoSync()
|
||
screenWidth.value = sys.screenWidth
|
||
})
|
||
|
||
// 拖拽状态
|
||
const startX = ref(0)
|
||
const dragging = ref(true)
|
||
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 = true
|
||
}
|
||
|
||
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 = true
|
||
// 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: 40vh;
|
||
// 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%;
|
||
z-index: -1;
|
||
}
|
||
|
||
.drawer-content-circle {
|
||
position: absolute;
|
||
bottom: 240rpx;
|
||
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> |