一、创建抽屉组件的基本结构
html
复制代码
<view class="drawer-container">
<view class="mask-container"></view>
<view class="content-container">
<slot></slot>
</view>
</view>
二、定义遮罩层、内容区域的基础样式
css
复制代码
.drawer-container {
position: fixed;
top: 0rpx;
left: 0rpx;
right: 0rpx;
bottom: 0rpx;
z-index: 999;
.mask-container {
display: block;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
opacity: 0;
background-color: rgba(15, 37, 41, 0.72);
transition: opacity 0.3s;
}
.content-container {
position: absolute;
right: -100%;
top: 0rpx;
bottom: 0rpx;
z-index: 999;
background-color: #ffffff;
transition: right 0.3s ease;
}
}
三、JS逻辑控制显隐
javascript
复制代码
import {
defineProps,
ref,
reactive,
defineExpose
} from 'vue'
/**
* width:内容区域的宽度
*/
const props = defineProps({
width: {
type: String,
default: '310px'
}
})
// 抽屉显隐控制数据
const that = reactive({
visible: false,
showDrawer: false
})
let watchTimer = null
// 打开抽屉
const open = () => {
if (that.visible) {
return
}
change('visible', 'showDrawer', true)
}
// 关闭抽屉
const close = () => {
if (!that.visible) {
return
}
change('showDrawer', 'visible', false)
}
// 抽屉显隐变化
const change = (param1, param2, status) => {
// 1、当抽屉关闭时:先控制showDrawer,使动画完成渲染,之后再操作visible关闭抽屉组件
// 2、当抽屉开启时:先控制visible开启抽屉组件,使抽屉组件渲染,再操作showDrawer,使动画完成渲染
that[param1] = status
if (watchTimer) {
clearTimeout(watchTimer)
}
watchTimer = setTimeout(() => {
that[param2] = status
}, status ? 50 : 300) // 这里的300是动画过渡时间(transition);50没有实际意义
}
// 暴露关闭、开启方法
defineExpose({
open,
close
})
四、visible控制组件显隐,showDrawer字段动态控制样式
html
复制代码
<view v-if="that.visible" class="drawer-container">
<!-- 点击遮罩关闭抽屉 -->
<view class="mask-container" :class="{'mask-visible': that.showDrawer}" @tap="close"></view>
<!-- 内容展示区域 -->
<view :style="{width}" class="content-container" :class="{'content-visible--right': that.showDrawer}">
<slot></slot>
</view>
</view>
五、添加过渡样式
css
复制代码
.content-visible--right {
right: 0;
}
.mask-visible {
display: block;
opacity: 1;
}
六、查看完整代码
javascript
复制代码
<template>
<view v-if="that.visible" class="drawer-container">
<!-- 点击遮罩关闭抽屉 -->
<view class="mask-container" :class="{'mask-visible': that.showDrawer}" @tap="close"></view>
<!-- 内容展示区域 -->
<view :style="{width}" class="content-container" :class="{'content-visible--right': that.showDrawer}">
<slot></slot>
</view>
</view>
</template>
<script setup>
import {
defineProps,
ref,
reactive,
defineExpose
} from 'vue'
/**
* width:内容区域的宽度
*/
const props = defineProps({
width: {
type: String,
default: '310px'
}
})
// 抽屉显隐控制数据
const that = reactive({
visible: false,
showDrawer: false
})
let watchTimer = null
// 打开抽屉
const open = () => {
if (that.visible) {
return
}
change('visible', 'showDrawer', true)
}
// 关闭抽屉
const close = () => {
if (!that.visible) {
return
}
change('showDrawer', 'visible', false)
}
// 抽屉显隐变化
const change = (param1, param2, status) => {
// 1、当抽屉关闭时:先控制showDrawer,使动画完成渲染,之后再操作visible关闭抽屉组件
// 2、当抽屉开启时:先控制visible开启抽屉组件,使抽屉组件渲染,再操作showDrawer,使动画完成渲染
that[param1] = status
if (watchTimer) {
clearTimeout(watchTimer)
}
watchTimer = setTimeout(() => {
that[param2] = status
}, status ? 50 : 300) // 这里的300是动画过渡时间(transition);50没有实际意义
}
// 暴露关闭、开启方法
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.drawer-container {
position: fixed;
top: 0rpx;
left: 0rpx;
right: 0rpx;
bottom: 0rpx;
z-index: 999;
.mask-container {
display: block;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
opacity: 0;
background-color: rgba(15, 37, 41, 0.72);
transition: opacity 0.3s;
}
.content-container {
position: absolute;
right: -100%;
top: 0rpx;
bottom: 0rpx;
z-index: 999;
background-color: #ffffff;
transition: right 0.3s ease;
}
.content-visible--right {
right: 0;
}
.mask-visible {
display: block;
opacity: 1;
}
}
</style>