2025-03-27 17:32:12 +08:00
|
|
|
|
<template>
|
|
|
|
|
<view>
|
2025-05-08 17:34:54 +08:00
|
|
|
|
<!-- 遮罩层,display 由 v-show 控制,opacity 由 overlay-show 类控制 -->
|
2025-05-13 17:18:07 +08:00
|
|
|
|
<view v-show="isVisible" :class="['overlay', { 'overlay-show': isVisible }]" @click="whiteDrawer" />
|
2025-05-08 17:34:54 +08:00
|
|
|
|
|
2025-03-27 17:32:12 +08:00
|
|
|
|
<!-- 抽屉 -->
|
2025-04-11 17:23:45 +08:00
|
|
|
|
<view :class="['drawer', { 'drawer-open': isVisible }]" :style="drawerStyle">
|
2025-03-27 17:32:12 +08:00
|
|
|
|
<view class="drawer-content">
|
2025-03-28 17:32:44 +08:00
|
|
|
|
<!-- 抽屉中间的半圆 -->
|
2025-05-13 17:18:07 +08:00
|
|
|
|
<view v-show="isVisible && canclose" class="drawer-content-circle" @click="whiteDrawer">
|
2025-03-28 17:32:44 +08:00
|
|
|
|
<image class="drawer-img" src="/static/index/zuoyuan.png" />
|
|
|
|
|
</view>
|
2025-03-27 17:32:12 +08:00
|
|
|
|
<!-- 抽屉内容 -->
|
|
|
|
|
<slot />
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import {
|
2025-04-11 17:23:45 +08:00
|
|
|
|
ref,
|
|
|
|
|
defineProps,
|
|
|
|
|
computed
|
2025-05-08 17:34:54 +08:00
|
|
|
|
} from 'vue'
|
|
|
|
|
|
|
|
|
|
// 控制抽屉显示隐藏
|
|
|
|
|
const isVisible = ref(false)
|
2025-03-27 17:32:12 +08:00
|
|
|
|
|
2025-05-08 17:34:54 +08:00
|
|
|
|
// 接收父组件传入的宽度百分比
|
2025-04-11 17:23:45 +08:00
|
|
|
|
const props = defineProps({
|
|
|
|
|
widNumber: {
|
|
|
|
|
type: Number,
|
2025-05-08 17:34:54 +08:00
|
|
|
|
default: 85
|
2025-05-13 17:18:07 +08:00
|
|
|
|
},
|
|
|
|
|
canclose: {
|
|
|
|
|
type:Boolean,
|
|
|
|
|
default:true
|
2025-04-11 17:23:45 +08:00
|
|
|
|
}
|
|
|
|
|
})
|
2025-05-08 17:34:54 +08:00
|
|
|
|
|
|
|
|
|
// 仅动态设置宽度,位置由 transform 控制
|
|
|
|
|
const drawerStyle = computed(() => ({
|
|
|
|
|
width: `${props.widNumber}%`
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
// 对外暴露打开方法
|
|
|
|
|
function openDrawer() {
|
|
|
|
|
isVisible.value = true
|
|
|
|
|
}
|
2025-05-13 17:18:07 +08:00
|
|
|
|
// 点击空白关闭方法
|
|
|
|
|
function whiteDrawer() {
|
|
|
|
|
if(props.canclose){
|
|
|
|
|
isVisible.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-08 17:34:54 +08:00
|
|
|
|
// 对外暴露关闭方法
|
|
|
|
|
function closeDrawer() {
|
|
|
|
|
isVisible.value = false
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-27 17:32:12 +08:00
|
|
|
|
defineExpose({
|
|
|
|
|
openDrawer,
|
2025-05-08 17:34:54 +08:00
|
|
|
|
closeDrawer
|
|
|
|
|
})
|
2025-03-27 17:32:12 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
2025-03-28 17:32:44 +08:00
|
|
|
|
<style lang="less" scoped>
|
2025-03-27 17:32:12 +08:00
|
|
|
|
/* 遮罩层样式 */
|
|
|
|
|
.overlay {
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 0;
|
|
|
|
|
left: 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100vh;
|
|
|
|
|
background: rgba(0, 0, 0, 0.5);
|
|
|
|
|
z-index: 999;
|
2025-05-08 17:34:54 +08:00
|
|
|
|
will-change: opacity;
|
|
|
|
|
transition: opacity 0.3s ease;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
display: block;
|
|
|
|
|
/* 由 v-show 控制 */
|
2025-03-27 17:32:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-08 17:34:54 +08:00
|
|
|
|
/* 当 isVisible 为 true 时,添加 overlay-show 类,触发遮罩渐显 */
|
|
|
|
|
.overlay-show {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 抽屉整体样式 */
|
2025-03-27 17:32:12 +08:00
|
|
|
|
.drawer {
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 0;
|
2025-05-08 17:34:54 +08:00
|
|
|
|
right: 0;
|
2025-03-27 17:32:12 +08:00
|
|
|
|
height: 100vh;
|
|
|
|
|
background: #fff;
|
|
|
|
|
z-index: 1000;
|
|
|
|
|
border-top-left-radius: 80rpx;
|
|
|
|
|
border-bottom-left-radius: 80rpx;
|
2025-05-08 17:34:54 +08:00
|
|
|
|
|
|
|
|
|
/* 使用 transform 做动画,避免布局重排 */
|
|
|
|
|
transform: translateX(100%);
|
|
|
|
|
transition: transform 0.4s ease;
|
|
|
|
|
will-change: transform;
|
2025-03-27 17:32:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-08 17:34:54 +08:00
|
|
|
|
/* 抽屉打开时 */
|
2025-03-27 17:32:12 +08:00
|
|
|
|
.drawer-open {
|
2025-05-08 17:34:54 +08:00
|
|
|
|
transform: translateX(0);
|
2025-03-27 17:32:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.drawer-content {
|
2025-03-28 17:32:44 +08:00
|
|
|
|
position: relative;
|
2025-05-08 17:34:54 +08:00
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
2025-03-28 17:32:44 +08:00
|
|
|
|
|
2025-05-08 17:34:54 +08:00
|
|
|
|
.drawer-content-circle {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: calc(50% - 55rpx);
|
|
|
|
|
left: -40rpx;
|
|
|
|
|
width: 100rpx;
|
|
|
|
|
height: 110rpx;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
z-index: -1;
|
|
|
|
|
background: linear-gradient(to bottom, #dfecfa, #c9dbee);
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
clip-path: inset(0 60% 0 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.drawer-img {
|
|
|
|
|
width: 25rpx;
|
|
|
|
|
height: 25rpx;
|
|
|
|
|
margin-left: 10rpx;
|
|
|
|
|
transform: rotate(180deg);
|
2025-03-27 17:32:12 +08:00
|
|
|
|
}
|
|
|
|
|
</style>
|