有些时候, Dialog 组件并不满足我们的需求, 比如你的表单很长, 亦或是你需要临时展示一些文档, Drawer 拥有和 Dialog 几乎相同的 API, 在 UI 上带来不一样的体验.
基础用法
- 呼出一个临时的侧边栏, 可以从多个方向呼出
- 你必须像 Dialog一样为 Drawer 设置 model-value 属性来控制 Drawer 的显示与隐藏状态,该属性接受一个 boolean 类型。
- Drawer 包含三部分: title & body & footer, 其中 title 是一个具名 slot, 你还可以通过 title 属性来设置标题, 默认情况下它是一个空字符串, 其中 body 部分是 Drawer 组件的主区域, 它包含了用户定义的主要内容. footer和title用法一致, 用来显示页脚信息.
- 当 Drawer 打开时,默认设置是从右至左打开 30% 浏览器宽度。 你可以通过传入对应的 direction 和 size 属性来修改这一默认行为。
<template>
<el-radio-group v-model="direction">
<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="drawer = true">
open
</el-button>
<el-button type="primary" style="margin-left: 16px" @click="drawer2 = true">
with footer
</el-button>
<el-drawer
v-model="drawer"
title="I am the title"
:direction="direction"
:before-close="handleClose"
>
<span>Hi, there!</span>
</el-drawer>
<el-drawer v-model="drawer2" :direction="direction">
<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>
</el-drawer>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'
import type { DrawerProps } from 'element-plus'
const drawer = ref(false)
const drawer2 = ref(false)
const direction = ref<DrawerProps['direction']>('rtl')
const radio1 = ref('Option 1')
const handleClose = (done: () => void) => {
ElMessageBox.confirm('Are you sure you want to close this?')
.then(() => {
done()
})
.catch(() => {
// catch error
})
}
function cancelClick() {
drawer2.value = false
}
function confirmClick() {
ElMessageBox.confirm(`Are you confirm to chose ${radio1.value} ?`)
.then(() => {
drawer2.value = false
})
.catch(() => {
// catch error
})
}
</script>
不添加 Title
- 当你不需要标题的时候,你可以将它移除。
- 通过设置 with-header 属性为 false 来控制是否显示标题。 如果你的应用需要具备可访问性,请务必设置好 title。
<template>
<el-button type="primary" style="margin-left: 16px" @click="drawer = true">
open
</el-button>
<el-drawer v-model="drawer" title="I am the title" :with-header="false">
<span>Hi there!</span>
</el-drawer>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const drawer = ref(false)
</script>
自定义内容
像 Dialog 组件一样,Drawer 也可以用来显示多种不同的交互。
<template>
<el-button text @click="table = true"
>Open Drawer with nested table</el-button
>
<el-button text @click="dialog = true"
>Open Drawer with nested form</el-button
>
<el-drawer
v-model="table"
title="I have a nested table inside!"
direction="rtl"
size="50%"
>
<el-table :data="gridData">
<el-table-column property="date" label="Date" width="150" />
<el-table-column property="name" label="Name" width="200" />
<el-table-column property="address" label="Address" />
</el-table>
</el-drawer>
<el-drawer
v-model="dialog"
title="I have a nested form inside!"
:before-close="handleClose"
direction="ltr"
class="demo-drawer"
>
<div class="demo-drawer__content">
<el-form :model="form">
<el-form-item label="Name" :label-width="formLabelWidth">
<el-input v-model="form.name" autocomplete="off" />
</el-form-item>
<el-form-item label="Area" :label-width="formLabelWidth">
<el-select
v-model="form.region"
placeholder="Please select activity area"
>
<el-option label="Area1" value="shanghai" />
<el-option label="Area2" value="beijing" />
</el-select>
</el-form-item>
</el-form>
<div class="demo-drawer__footer">
<el-button @click="cancelForm">Cancel</el-button>
<el-button type="primary" :loading="loading" @click="onClick">
{{ loading ? 'Submitting ...' : 'Submit' }}
</el-button>
</div>
</div>
</el-drawer>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { ElMessageBox } from 'element-plus'
const formLabelWidth = '80px'
let timer
const table = ref(false)
const dialog = ref(false)
const loading = ref(false)
const form = reactive({
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
})
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 onClick = () => {
loading.value = true
setTimeout(() => {
loading.value = false
dialog.value = false
}, 400)
}
const handleClose = (done) => {
if (loading.value) {
return
}
ElMessageBox.confirm('Do you want to submit?')
.then(() => {
loading.value = true
timer = setTimeout(() => {
done()
// 动画关闭需要一定的时间
setTimeout(() => {
loading.value = false
}, 400)
}, 2000)
})
.catch(() => {
// catch error
})
}
const cancelForm = () => {
loading.value = false
dialog.value = false
clearTimeout(timer)
}
</script>
自定义头部
- header 可用于自定义显示标题的区域。
- 为了保持可用性,除了使用此插槽外,使用 title 属性,或使用 titleId 插槽属性来指定哪些元素应该读取为抽屉标题。
<template>
<el-button @click="visible = true">
Open Drawer with customized header
</el-button>
<el-drawer v-model="visible" :show-close="false">
<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.
</el-drawer>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { CircleCloseFilled } from '@element-plus/icons-vue'
const visible = ref(false)
</script>
嵌套抽屉
- 你可以像 Dialog 一样拥有多层嵌套的 Drawer
- 如果你需要在不同图层中多个抽屉,你必须设置 append-to-body 属性到 true
<template>
<el-button type="primary" style="margin-left: 16px" @click="drawer = true">
open
</el-button>
<el-drawer v-model="drawer" title="I'm outer Drawer" size="50%">
<div>
<el-button @click="innerDrawer = true">Click me!</el-button>
<el-drawer
v-model="innerDrawer"
title="I'm inner Drawer"
:append-to-body="true"
:before-close="handleClose"
>
<p>_(:зゝ∠)_</p>
</el-drawer>
</div>
</el-drawer>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'
const drawer = ref(false)
const innerDrawer = ref(false)
const handleClose = (done: () => void) => {
ElMessageBox.confirm('You still have unsaved data, proceed?')
.then(() => {
done()
})
.catch(() => {
// catch error
})
}
</script>