Drawer Component Design Document
Overview
The Drawer component is a core component in this component library used to implement drawer-style popup functionality. It continues the consistent design philosophy of our component library, adopting the principles of "containerization" and "animation-driven" design. It implements a complete and easy-to-use drawer-style popup solution through drawer.vue.
The Drawer component focuses on handling temporary content display on the side of the page, providing users with a smooth and intuitive drawer-style interaction experience. It supports multiple directions, size configurations, custom styles, and rich interaction controls, effectively improving user experience when viewing additional information or performing auxiliary operations.
Design Philosophy
Containerized Design
The Drawer component adopts a containerized design approach:
- Independent Container - Renders the component to the body via Teleport to ensure correct layering and positioning
- Complete Structure - Built-in title, content, and footer areas to provide a full container structure
- State Isolation - Internally manages display state, decoupled from external application logic
This design ensures the component’s independence and reusability.
Animation-Driven Architecture
The Drawer component adopts an animation-driven architecture:
- Transition Animation - Implements fade and slide animations for the mask and drawer body using the Transition component
- Direction Awareness - Animation effects automatically adjust based on the direction property
- State Synchronization - Animation state is tightly coupled with the component’s display state
This design makes the interaction experience smoother and more natural while keeping the code clear.
Core Feature Design
Display Control Mechanism
The core of the Drawer component lies in its display control mechanism:
const visible = ref(props.modelValue)
watch(
() => props.modelValue,
(val) => {
visible.value = val
if (val) {
openDrawer()
} else {
closeDrawer()
}
}
)Display Control Features:
- Two-way Binding - Achieves v-model two-way binding through modelValue
- State Synchronization - Keeps internal state consistent with external state
- Lifecycle Management - Triggers corresponding lifecycle events when opening/closing
- Scroll Control - Controls page scrolling through the lockScroll property
Direction and Size Management
The Drawer component’s direction and size management is designed as follows:
const drawerStyle = computed(() => {
if (['rtl', 'ltr'].includes(props.direction)) {
return {
width:
typeof props.size === 'number'
? `${props.size}px`
: props.size
}
} else {
return {
height:
typeof props.size === 'number'
? `${props.size}px`
: props.size
}
}
})Direction and Size Features:
- Multi-Direction Support - Supports four directions: ltr, rtl, ttb, btt
- Flexible Sizing - Supports both percentage and pixel values
- Adaptive Layout - Automatically adjusts width or height based on direction
- Responsive Design - Adapts to different screen sizes
Component Structure Design
Overall Structure
The overall structure of the Drawer component is as follows:
<Teleport to="body">
<div v-if="visible" class="my-drawer__wrapper">
<!-- Mask layer -->
<Transition name="my-drawer-fade">
<div v-show="visible" class="my-drawer__mask" @click="handleMaskClick" />
</Transition>
<!-- Drawer body -->
<Transition name="my-drawer-slide" :style="dialogStyle">
<div v-if="visible" class="my-drawer" :class="`my-drawer--${props.direction}`" :style="drawerStyle">
<!-- Header -->
<header class="my-drawer__header" v-if="props.withHeader">
<slot name="title">{{ props.title }}</slot>
<button class="my-drawer__close" @click="handleClose" v-if="props.showClose">
×
</button>
</header>
<!-- Body -->
<section class="my-drawer__body">
<slot></slot>
</section>
<!-- Footer -->
<footer class="my-drawer__footer" v-if="$slots.footer">
<slot name="footer"></slot>
</footer>
</div>
</Transition>
</div>
</Teleport>Component Hierarchy
The Drawer component contains several key parts:
- Wrapper Layer -
.my-drawer__wrapper- Wraps the entire drawer component with fixed positioning - Mask Layer -
.my-drawer__mask- Background mask; clicking can close the drawer - Drawer Body -
.my-drawer- Main content area of the drawer - Header Area -
.my-drawer__header- Title and close button area - Content Area -
.my-drawer__body- Primary content display area - Footer Area -
.my-drawer__footer- Footer content such as action buttons
Direction Class Design:
.my-drawer--rtl- Slides in from right to left.my-drawer--ltr- Slides in from left to right.my-drawer--ttb- Slides in from top to bottom.my-drawer--btt- Slides in from bottom to top
Interaction Design
Close Mechanism
The Drawer component provides multiple ways to close:
const handleClose = () => {
if (props.beforeClose) {
props.beforeClose(closeDrawer)
} else {
closeDrawer()
}
}
const handleMaskClick = () => {
if (props.closeOnClickModal) {
handleClose()
}
}
onMounted(() => {
if (props.closeOnPressEscape) {
window.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && visible.value) {
handleClose()
}
})
}
})Close Methods:
- Close Button - Click the close button in the header area
- Mask Click - Click the mask to close (configurable)
- ESC Key - Press ESC to close (configurable)
- Custom Close - Implement custom close logic through the beforeClose callback
Animation Implementation
The Drawer component uses a carefully designed transition strategy for animations:
/* Mask fade in/out */
.my-drawer-fade-enter-active,
.my-drawer-fade-leave-active {
transition: opacity 0.3s ease-in-out;
}
.my-drawer-fade-enter-from,
.my-drawer-fade-leave-to {
opacity: 0;
}
/* Drawer slide animation */
.my-drawer-slide-enter-active,
.my-drawer-slide-leave-active {
transition: transform 0.4s ease-in-out, opacity 0.4s ease-in-out;
}
.my-drawer-slide-enter-from,
.my-drawer-slide-leave-to {
opacity: 0.9;
}Animation Features:
- Mask Layer - Uses fade in/out effect
- Drawer Body - Uses slide + slight scale effect
- Direction Adaptation - Automatically adjusts animation direction based on the direction property
- Visual Feedback - Adds slight scale effect to enhance visual feedback
Extensibility Design
The Drawer component has excellent extensibility:
- Direction Extension - Supports four directions through the direction property
- Size Extension - Supports flexible size configuration through the size property
- Content Extension - Supports custom title, content, and footer through slots
- Style Extension - Supports custom background color through the backgroundColor property
- Interaction Extension - Supports custom interaction logic through beforeClose and event mechanisms
Style Details
The Drawer component has the following characteristics in style handling:
- Hierarchical Structure - Precisely controls element stacking order through z-indexscss
.my-drawer__wrapper { position: fixed; inset: 0; z-index: 3000; } .my-drawer__mask { z-index: 2000; } .my-drawer { z-index: 2100; } - Animation Optimization - Uses high-performance transform and opacity properties
- Visual Hierarchy - Creates clear visual hierarchy through borders, shadows, and spacing
- Responsive Design - Adapts to different screen sizes and directions
- Transition Effects - Uses easing functions (ease-in-out) for more natural animations
Performance Optimization
Performance is optimized through the following methods:
- Conditional Rendering - Renders drawer content only when neededhtml
<div v-if="visible" class="my-drawer__wrapper"> - Efficient Animation - Uses transform and opacity for GPU-accelerated animations
- Event Management - Listens and removes events on demand
- Scroll Control - Disables page scrolling only when the drawer is open
- Memory Management - Properly releases resources after the drawer is closed
Design Value
The Drawer component continues the design philosophy of our component library:
- Separation of Concerns - Clearly separates structure, styles, and logic
- Containerized Design - Provides a complete drawer container to reduce usage complexity
- Animation-Driven - Enhances user experience through carefully designed animations
- Multi-Direction Support - Meets drawer display needs in different scenarios
- Customizability - Provides high customization capability through rich properties and slots