提供9个字段对drawer组件进行控制:
modelValue: 对抽屉显示隐藏进行控制,
width: 控制抽屉的宽度,
title: 控制抽屉的标题,
appendToBody: 是否将抽屉添加至body,
closeOnClickModal: 是否点击遮罩层关闭抽屉,
showConfirm: 是否显示确认按钮,
showCancel: 是否显示取消按钮,
cancelText: 取消按钮的文本,
confirmText: 确认按钮的文本
drawer.vue代码如下
<template>
<teleport v-if="appendToBody" to="body">
<transition name="drawer-fade">
<div v-show="visible" class="drawer-overlay" @click.self="handleCloseModal">
<div class="drawer-content" :style="drawerStyle" @click.stop>
<div class="drawer-header">
<div class="title-content">
<div class="drawer-close-button" @click="handleClose">X</div>
<span>{{ title }}</span>
</div>
<div class="drawer-btn">
<div v-if="showCancel" class="drawer-button" @click="handleCancel">{{ cancelText }}</div>
<div v-if="showConfirm" class="drawer-button" @click="handleSure">{{ confirmText }}</div>
</div>
</div>
<div class="mes-drawer-layout-main">
<slot></slot>
</div>
</div>
</div>
</transition>
</teleport>
<transition name="drawer-fade" v-else>
<div v-show="visible" class="drawer-overlay" @click.self="handleCloseModal">
<div class="drawer-content" :style="drawerStyle" @click.stop>
<div class="drawer-header">
<div class="title-content">
<div class="drawer-close-button" @click="handleClose">X</div>
<span>{{ title }}</span>
</div>
<div class="drawer-btn">
<div v-if="showCancel" class="drawer-button" @click="handleCancel">{{ cancelText }}</div>
<div v-if="showConfirm" class="drawer-button" @click="handleSure">{{ confirmText }}</div>
</div>
</div>
<div class="mes-drawer-layout-main">
<slot></slot>
</div>
</div>
</div>
</transition>
</template>
<script lang="ts" setup>
import { ref, watch, computed } from "vue";
const props = withDefaults(
defineProps<{
modelValue?: boolean;
width?: string;
title?: string;
appendToBody?: boolean;
closeOnClickModal?: boolean;
showConfirm?: boolean;
showCancel?: boolean;
cancelText?: string;
confirmText?: string;
}>(),
{
modelValue: false,
width: "30%",
title: "",
appendToBody: true,
closeOnClickModal: false,
showConfirm: true,
showCancel: true,
cancelText: "取消",
confirmText: "确认"
}
);
const emit = defineEmits<{
(event: "update:modelValue", value: boolean): void;
(event: "beforeClose"): void;
(event: "on-cancel"): void;
(event: "on-sure"): void;
}>();
const visible = ref(props.modelValue);
watch(
() => props.modelValue,
newVal => {
visible.value = newVal;
}
);
const drawerStyle = computed(() => ({
width: props.width,
height: "100%"
}));
function handleCloseModal() {
if (props.closeOnClickModal) {
handleClose();
}
}
function handleClose() {
emit("beforeClose");
emit("update:modelValue", false);
}
function handleCancel() {
emit("on-cancel");
}
function handleSure() {
emit("on-sure");
}
</script>
<style lang="scss" scoped>
.drawer-overlay {
z-index: 999;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: flex-end;
align-items: center;
.drawer-content {
background: #333333;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: transform 0.3s ease;
position: relative;
z-index: 1000;
display: flex;
flex-direction: column;
.drawer-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 56px;
padding: 0 16px;
border-bottom: 1px solid #efefef;
color: #ffffff;
.title-content {
display: flex;
align-items: center;
span {
margin-left: 12px;
}
.drawer-close-button {
font-size: 16px;
cursor: pointer;
}
}
.drawer-btn {
display: flex;
justify-content: flex-end;
padding: 10px;
.drawer-button {
margin-left: 10px;
display: inline-flex;
justify-content: center;
align-items: center;
line-height: 1;
height: 32px;
white-space: nowrap;
cursor: pointer;
color: #fff;
text-align: center;
box-sizing: border-box;
outline: 0;
transition: 0.1s;
font-weight: 500;
-webkit-user-select: none;
user-select: none;
vertical-align: middle;
-webkit-appearance: none;
background-color: #2478f2;
border: 1px solid #dcdfe6;
border-color: #2478f2;
padding: 8px 15px;
font-size: 14px;
border-radius: 4px;
}
}
}
.mes-drawer-layout-main {
padding: 16px;
box-sizing: border-box;
flex: 1;
color: #ffffff;
}
}
}
</style>
<style>
.drawer-fade-enter-active,
.drawer-fade-leave-active {
transition: opacity 0.3s ease;
}
.drawer-fade-enter,
.drawer-fade-leave-to {
opacity: 0;
}
</style>
使用方式:
<template>
<Drawer
v-model="showDrawer"
width="500px"
title="抽屉"
@before-close="drawerBeforeClose"
@on-sure="handleDrawerSure"
@on-cancel="handleDrawerCancel"
>
<p>This is the drawer content</p>
</Drawer>
</template>
<script setup lang="ts">
import { ref } from "vue";
import Drawer from "@/components/Drawer/index.vue";
const showDrawer = ref(false);
const handleShowDetails = () => {
console.log("跳转到详情页");
showDrawer.value = true;
};
const drawerBeforeClose = () => {
console.log("抽屉关闭前");
showDrawer.value = false;
};
const handleDrawerSure = () => {
console.log("抽屉确认");
showDrawer.value = false;
};
const handleDrawerCancel = () => {
console.log("抽屉取消");
showDrawer.value = false;
};
</script>