vue实现抽屉组件
实现基础抽屉组件结构
使用 Vue 的单文件组件方式创建抽屉组件,核心结构包含遮罩层、抽屉主体和内容插槽:
<template>
<div class="drawer-container">
<div
class="drawer-mask"
v-show="visible"
@click="handleMaskClick">
</div>
<div
class="drawer-wrapper"
:class="[placement, { 'visible': visible }]">
<div class="drawer-content">
<slot></slot>
</div>
</div>
</div>
</template>
定义组件属性与事件
通过 props 控制抽屉行为,包括显示状态、位置和点击遮罩是否关闭:
<script>
export default {
props: {
visible: {
type: Boolean,
default: false
},
placement: {
type: String,
default: 'right',
validator: (value) => ['top', 'right', 'bottom', 'left'].includes(value)
},
maskClosable: {
type: Boolean,
default: true
}
},
methods: {
handleMaskClick() {
if (this.maskClosable) {
this.$emit('update:visible', false);
}
}
}
}
</script>
添加基础样式
实现抽屉动画效果和不同位置的定位:
<style scoped>
.drawer-container {
position: relative;
}
.drawer-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
}
.drawer-wrapper {
position: fixed;
z-index: 1001;
transition: all 0.3s;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.drawer-wrapper.right {
top: 0;
right: 0;
height: 100%;
transform: translateX(100%);
}
.drawer-wrapper.left {
top: 0;
left: 0;
height: 100%;
transform: translateX(-100%);
}
.drawer-wrapper.top {
top: 0;
left: 0;
width: 100%;
transform: translateY(-100%);
}
.drawer-wrapper.bottom {
bottom: 0;
left: 0;
width: 100%;
transform: translateY(100%);
}
.drawer-wrapper.visible.right,
.drawer-wrapper.visible.left {
transform: translateX(0);
}
.drawer-wrapper.visible.top,
.drawer-wrapper.visible.bottom {
transform: translateY(0);
}
.drawer-content {
width: 100%;
height: 100%;
overflow: auto;
}
</style>
添加标题和关闭按钮
增强抽屉组件的功能性,添加标题栏和关闭控制:
<template>
<!-- 原有结构基础上添加 -->
<div class="drawer-header" v-if="title || showClose">
<span class="drawer-title">{{ title }}</span>
<button
v-if="showClose"
class="drawer-close"
@click="$emit('update:visible', false)">
×
</button>
</div>
</template>
<script>
export default {
props: {
title: String,
showClose: {
type: Boolean,
default: true
}
// 其他原有props...
}
}
</script>
<style scoped>
.drawer-header {
padding: 16px 24px;
border-bottom: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
align-items: center;
}
.drawer-title {
font-size: 16px;
font-weight: 500;
}
.drawer-close {
font-size: 18px;
cursor: pointer;
background: transparent;
border: none;
}
</style>
控制抽屉宽度/高度
通过 props 允许自定义抽屉尺寸:
props: {
width: {
type: [String, Number],
default: '30%'
},
height: {
type: [String, Number],
default: '30%'
}
}
<div
class="drawer-wrapper"
:class="[placement, { 'visible': visible }]"
:style="placement === 'left' || placement === 'right'
? { width: typeof width === 'number' ? `${width}px` : width }
: { height: typeof height === 'number' ? `${height}px` : height }">
<!-- 内容不变 -->
</div>
实现嵌套抽屉支持
修改 z-index 策略避免嵌套抽屉冲突:
data() {
return {
zIndex: this.getNextZIndex()
};
},
methods: {
getNextZIndex() {
let zIndex = 1000;
const drawers = document.querySelectorAll('.drawer-mask');
if (drawers.length > 0) {
zIndex = Number(window.getComputedStyle(drawers[drawers.length - 1]).zIndex) + 1;
}
return zIndex;
}
}
<div
class="drawer-mask"
v-show="visible"
:style="{ zIndex }"
@click="handleMaskClick">
</div>
<div
class="drawer-wrapper"
:style="{
zIndex: zIndex + 1,
...placementStyle
}">
<!-- 内容不变 -->
</div>






