使用Vue3写一个抽屉Drawer组件

一、创建抽屉组件的基本结构

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>
相关推荐
励志成为嵌入式工程师21 分钟前
c语言简单编程练习9
c语言·开发语言·算法·vim
逐·風23 分钟前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
捕鲸叉1 小时前
创建线程时传递参数给线程
开发语言·c++·算法
Devil枫1 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
A charmer1 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq1 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
尚梦1 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子2 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
记录成长java2 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山2 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js