useDrawer
useDrawer 返回 Drawer 组件以及 open、close 等方法。Drawer 组件支持 ElDrawer 原有的属性、插槽和事件。
基础用法
set title by slot
vue
<script setup lang="ts">
import { useDrawer, useMessageBox } from 'element-hooks';
import { type DrawerProps } from 'element-plus';
import { ref } from 'vue';
const direction = ref<DrawerProps['direction']>('rtl');
const radio1 = ref('Option 1');
const { confirm } = useMessageBox();
const handleClose = async (done: () => void) => {
const isConfirmed = await confirm('Are you sure you want to close this?');
if (isConfirmed) {
done();
}
};
const [Drawer, { open, setState }] = useDrawer({
title: 'I am the title',
direction: direction.value,
beforeClose: handleClose,
});
const [
DrawerWithFooter,
{
open: openDrawerWithFooter,
close: closeDrawerWithFooter,
setState: setDrawerWithFooterState,
},
] = useDrawer({
direction: direction.value,
});
const handleDirectionChange = () => {
setState(prev => ({ ...prev, direction: direction.value }));
setDrawerWithFooterState(prev => ({ ...prev, direction: direction.value }));
};
function cancelClick() {
closeDrawerWithFooter();
}
async function confirmClick() {
const isConfirmed = await confirm(
`Are you confirm to chose ${radio1.value} ?`,
);
if (isConfirmed) {
closeDrawerWithFooter();
}
}
</script>
<template>
<el-radio-group v-model="direction" @change="handleDirectionChange">
<el-radio value="ltr">left to right</el-radio>
<el-radio value="rtl">right to left</el-radio>
<el-radio value="ttb">top to bottom</el-radio>
<el-radio value="btt">bottom to top</el-radio>
</el-radio-group>
<el-button type="primary" style="margin-left: 16px" @click="open">
open
</el-button>
<el-button
type="primary"
style="margin-left: 16px"
@click="openDrawerWithFooter"
>
with footer
</el-button>
<Drawer>
<span>Hi, there!</span>
</Drawer>
<DrawerWithFooter>
<template #header>
<h4>set title by slot</h4>
</template>
<template #default>
<div>
<el-radio v-model="radio1" value="Option 1" size="large">
Option 1
</el-radio>
<el-radio v-model="radio1" value="Option 2" size="large">
Option 2
</el-radio>
</div>
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="cancelClick">cancel</el-button>
<el-button type="primary" @click="confirmClick">confirm</el-button>
</div>
</template>
</DrawerWithFooter>
</template>不添加 Title
vue
<script setup lang="ts">
import { useDrawer } from 'element-hooks';
const [Drawer, { open }] = useDrawer({
title: 'I am the title',
withHeader: false,
});
</script>
<template>
<el-button type="primary" @click="open">open</el-button>
<Drawer>
<span>Hi there!</span>
</Drawer>
</template>自定义内容
vue
<script setup lang="ts">
import { useDrawer, useForm, useMessageBox, useTable } from 'element-hooks';
import { ElInput, ElSelect } from 'element-plus';
import { ref } from 'vue';
const formLabelWidth = '80px';
let timer: ReturnType<typeof setTimeout> | undefined;
const loading = ref(false);
const { confirm } = useMessageBox();
const gridData = [
{
date: '2016-05-02',
name: 'Peter Parker',
address: 'Queens, New York City',
},
{
date: '2016-05-04',
name: 'Peter Parker',
address: 'Queens, New York City',
},
{
date: '2016-05-01',
name: 'Peter Parker',
address: 'Queens, New York City',
},
{
date: '2016-05-03',
name: 'Peter Parker',
address: 'Queens, New York City',
},
];
const [Table] = useTable({
data: gridData,
columns: [
{ prop: 'date', label: 'Date', width: 150 },
{ prop: 'name', label: 'Name', width: 200 },
{ prop: 'address', label: 'Address' },
],
});
const [Form] = useForm({
model: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
},
items: [
{
label: 'Name',
labelWidth: formLabelWidth,
prop: 'name',
render: {
component: ElInput,
props: { autocomplete: 'off' },
},
},
{
label: 'Area',
labelWidth: formLabelWidth,
prop: 'region',
render: {
component: ElSelect,
props: {
placeholder: 'Please select activity area',
options: [
{ label: 'Area1', value: 'shanghai' },
{ label: 'Area2', value: 'beijing' },
],
},
},
},
],
});
const [TableDrawer, { open: openTableDrawer }] = useDrawer({
title: 'I have a nested table inside!',
direction: 'rtl',
size: '50%',
});
const handleClose = async (done: () => void) => {
if (loading.value) {
return;
}
const isConfirmed = await confirm('Do you want to submit?');
if (isConfirmed) {
loading.value = true;
timer = setTimeout(() => {
done();
// 动画关闭需要一定的时间
setTimeout(() => {
loading.value = false;
}, 400);
}, 2000);
}
};
const [FormDrawer, { open: openFormDrawer, close: closeFormDrawer }] =
useDrawer({
title: 'I have a nested form inside!',
beforeClose: handleClose,
direction: 'ltr',
class: 'demo-drawer',
});
const handleSubmit = () => {
loading.value = true;
setTimeout(() => {
loading.value = false;
closeFormDrawer();
}, 400);
};
const cancelForm = () => {
loading.value = false;
closeFormDrawer();
clearTimeout(timer);
};
</script>
<template>
<el-button text @click="openTableDrawer">
Open Drawer with nested table
</el-button>
<el-button text @click="openFormDrawer">
Open Drawer with nested form
</el-button>
<TableDrawer>
<Table />
</TableDrawer>
<FormDrawer>
<div class="demo-drawer__content">
<Form />
<div class="demo-drawer__footer">
<el-button @click="cancelForm">Cancel</el-button>
<el-button type="primary" :loading="loading" @click="handleSubmit">
{{ loading ? 'Submitting ...' : 'Submit' }}
</el-button>
</div>
</div>
</FormDrawer>
</template>自定义头部
This is a custom header!
vue
<script setup lang="ts">
import { CircleCloseFilled } from '@element-plus/icons-vue';
import { useDrawer } from 'element-hooks';
const [Drawer, { open }] = useDrawer({
showClose: false,
});
</script>
<template>
<el-button @click="open">Open Drawer with customized header</el-button>
<Drawer>
<template #header="{ close, titleId, titleClass }">
<h4 :id="titleId" :class="titleClass">This is a custom header!</h4>
<el-button type="danger" @click="close">
<el-icon class="el-icon--left"><CircleCloseFilled /></el-icon>
Close
</el-button>
</template>
This is drawer content.
</Drawer>
</template>可调整抽屉
vue
<script setup lang="ts">
import { useDrawer } from 'element-hooks';
import { type DrawerProps } from 'element-plus';
import { ref } from 'vue';
const direction = ref<DrawerProps['direction']>();
const [Drawer, { open, setState }] = useDrawer({
resizable: true,
});
const handleDirectionChange = () => {
setState(prev => ({ ...prev, direction: direction.value }));
open();
};
</script>
<template>
<el-radio-group v-model="direction" @change="handleDirectionChange">
<el-radio-button value="ttb">top</el-radio-button>
<el-radio-button value="rtl">right</el-radio-button>
<el-radio-button value="btt">bottom</el-radio-button>
<el-radio-button value="ltr">left</el-radio-button>
</el-radio-group>
<Drawer>This is drawer content.</Drawer>
</template>嵌套抽屉
vue
<script setup lang="ts">
import { useDrawer, useMessageBox } from 'element-hooks';
const { confirm } = useMessageBox();
const handleClose = async (done: () => void) => {
const isConfirmed = await confirm('You still have unsaved data, proceed?');
if (isConfirmed) {
done();
}
};
const [OuterDrawer, { open: openOuterDrawer }] = useDrawer({
title: "I'm outer Drawer",
size: '50%',
});
const [InnerDrawer, { open: openInnerDrawer }] = useDrawer({
title: "I'm inner Drawer",
appendToBody: true,
beforeClose: handleClose,
});
</script>
<template>
<el-button type="primary" @click="openOuterDrawer">open</el-button>
<OuterDrawer>
<div>
<el-button @click="openInnerDrawer">Click me!</el-button>
<InnerDrawer>
<p>_(:зゝ∠)_</p>
</InnerDrawer>
</div>
</OuterDrawer>
</template>模态框
vue
<script setup lang="ts">
import { useDrawer } from 'element-hooks';
const [Drawer, { open, close }] = useDrawer({
modal: false,
modalPenetrable: true,
});
</script>
<template>
<el-button plain @click="open">Open the modal Drawer</el-button>
<Drawer>
<span>It's a modal Drawer</span>
<template #footer>
<div class="drawer-footer">
<el-button @click="close">Cancel</el-button>
<el-button type="primary" @click="close">Confirm</el-button>
</div>
</template>
</Drawer>
</template>API
Options
useDrawer 支持 ElDrawer 的属性。modelValue 由 Hook 内部管理,因此不对外暴露。
更多属性请参考 Element Plus Drawer Props。
Controller
| 成员 | 说明 | 类型 |
|---|---|---|
open | 打开抽屉 | () => void |
close | 关闭抽屉 | () => void |
getVisible | 获取当前抽屉的可见状态 | () => boolean |
setState | 更新抽屉的配置属性 | (state: DrawerOptions | ((prev: DrawerOptions) => DrawerOptions)) => void |
setTitle | 更新抽屉标题 | (title: string | undefined | ((prev: string | undefined) => string | undefined)) => void |
instance | ElDrawer 组件实例引用 | Ref<DrawerInstance | null> |