drawer 抽屉
不同方向
抽屉弹出的方式分为 左 上 右 下四种方式,默认是从右侧弹出。
<template>
<cl-button-group>
<cl-button @click="openDrawer('top')"> 上 </cl-button>
<cl-button @click="openDrawer('right')"> 右 </cl-button>
<cl-button @click="openDrawer('bottom')"> 下 </cl-button>
<cl-button @click="openDrawer('left')"> 左 </cl-button>
</cl-button-group>
<cl-drawer v-model:show="show" :placement="placement">从 {{ placement }} 方向弹出抽屉</cl-drawer>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const show = ref(false)
const placement = ref('right')
const openDrawer = (place) => {
show.value = true
placement.value = place
}
return {
show,
placement,
openDrawer
}
}
})
</script>
size取值分为small / default / large 默认取值default
在左右弹出的情况下:small对应长度320px, default对应长度400px, large对应长度560px
在上下弹出的情况下:small对应长度40%, default对应长度60%, large对应长度80%
在width和size同时存在的情况下,以width优先,height同理
设置抽屉的宽高
width / height / size 的区别
<template>
<div>
<cl-button @click="unSetSize" style="margin: 5px">未设置宽度</cl-button>
<cl-button @click="setLargeSize" style="margin: 5px">未设置width,size设为large</cl-button>
</div>
<div>
<cl-button @click="unSetSizeFromBottomOpen" style="margin: 5px"
>未设置高度,从底部弹出</cl-button
>
<cl-button @click="setLargeSizeFromBottomOpen">未设置height,size设为large</cl-button>
</div>
<div>
<cl-button @click="setWidth" style="margin: 5px">设置width</cl-button>
</div>
<p>size取值分为small / default / large 默认取值default</p>
<p>在左右弹出的情况下:small对应长度320px, default对应长度400px, large对应长度560px</p>
<p>在上下弹出的情况下:small对应长度40%, default对应长度60%, large对应长度80%</p>
<p style="color: red">在width和size同时存在的情况下,以width优先,height同理</p>
<cl-drawer v-model:show="show" :size="size" :placement="placement" :width="width"
>通过size、width、height给抽屉设置宽高</cl-drawer
>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const show = ref(false)
const size = ref('default')
const placement = ref('right')
const width = ref(0)
const unSetSize = () => {
placement.value = 'right'
show.value = true
size.value = 'default'
}
const setLargeSize = () => {
placement.value = 'right'
show.value = true
size.value = 'large'
width.value = 0
}
const unSetSizeFromBottomOpen = () => {
placement.value = 'bottom'
show.value = true
size.value = 'default'
width.value = 0
}
const setLargeSizeFromBottomOpen = () => {
placement.value = 'bottom'
show.value = true
size.value = 'large'
width.value = 0
}
const setWidth = () => {
placement.value = 'right'
show.value = true
width.value = 600
}
return {
show,
size,
placement,
width,
unSetSize,
setLargeSize,
unSetSizeFromBottomOpen,
setLargeSizeFromBottomOpen,
setWidth
}
}
})
</script>
可拖拽
<template>
<cl-button @click="openDrawerTop" style="margin: 5px"> 上下拖动 </cl-button>
<cl-button @click="openDrawerLeft" style="margin: 5px"> 左右拖动 </cl-button>
<cl-drawer
v-model:show="show"
:placement="placement"
v-model:height="height"
v-model:width="width"
resizable
>
<template v-slot:header>可以拖动的弹窗</template>
从 {{ placement }} 方向拖动弹窗
</cl-drawer>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const show = ref(false)
const placement = ref()
const width = ref(500)
const height = ref(300)
const openDrawerTop = () => {
show.value = true
placement.value = 'top'
}
const openDrawerLeft = () => {
show.value = true
placement.value = 'left'
}
return {
openDrawerTop,
openDrawerLeft,
placement,
show,
height,
width
}
}
})
</script>
多层嵌套的抽屉
<template>
<cl-button @click="openFirstDrawer" style="margin: 5px">第一层抽屉</cl-button>
<cl-drawer v-model:show="outerShow" :width="600">
<template v-slot:header>第一层抽屉</template>
<cl-button @click="openSecondDrawer" style="margin: 5px">第二层抽屉</cl-button>
<cl-drawer v-model:show="innerShow" v-model:width="innerWidth" resizable>
<template v-slot:header>第二层抽屉</template>
</cl-drawer>
</cl-drawer>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const outerShow = ref(false)
const innerShow = ref(false)
const innerWidth = ref(300)
const openFirstDrawer = () => {
outerShow.value = true
}
const openSecondDrawer = () => {
innerShow.value = true
}
return {
outerShow,
innerShow,
openFirstDrawer,
openSecondDrawer,
innerWidth
}
}
})
</script>
在该容器内部打开抽屉
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏
在容器内部打开抽屉
<template>
<cl-button @click="openDrawer('top')"> 上 </cl-button>
<cl-button @click="openDrawer('right')"> 右 </cl-button>
<cl-button @click="openDrawer('bottom')"> 下 </cl-button>
<cl-button @click="openDrawer('left')"> 左 </cl-button>
<cl-drawer
v-model:show="outerShow"
:placement="placement"
to=".drawer-demo-container"
resizable
v-model:height="height"
v-model:width="width"
></cl-drawer>
<div class="drawer-demo-container">
<div class="scroll-container">
<p>在该容器内部打开抽屉</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
<p>测试有滚动条的情况下,抽屉打开时,滚动条是否隐藏</p>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const outerShow = ref(false)
const height = ref(100)
const width = ref(100)
const placement = ref('right')
const openDrawer = (place) => {
outerShow.value = true
placement.value = place
}
return {
outerShow,
placement,
openDrawer,
height,
width
}
}
})
</script>
<style scoped>
.drawer-demo-container {
position: relative;
width: 600px;
height: 400px;
overflow: hidden;
margin-top: 10px;
border: 1px solid #10b981;
}
.scroll-container {
width: 100%;
height: 100%;
padding: 10px 20px;
color: #10b981;
overflow: auto;
}
</style>
props.title 和 slots.header 同时存在时,slot优先级更高
<template>
<cl-button @click="openDrawer">自定义内容</cl-button>
<cl-drawer v-model:show="show" title="标题props">
<template v-slot:header>Taylor Swift</template>
</cl-drawer>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const show = ref(false)
const openDrawer = () => {
show.value = true
}
return {
show,
openDrawer
}
}
})
</script>
自定义内容
<template>
<cl-button @click="openDrawer">自定义内容</cl-button>
<cl-drawer v-model:show="show" v-model:width="width" resizable>
<template v-slot:header>Taylor Swift</template>
<template v-slot:close-icon>
<cl-icon iconName="cl-icon-circle-close"></cl-icon>
</template>
<div>She is an excellent singer.</div>
<div>
Swift began professional songwriting at age 14 and signed with Big Machine Records in 2005 to
become a country singer. Under Big Machine, she released six studio albums, four of them to
country radio, starting with her self-titled album in 2006. Her next, Fearless (2008),
explored country pop, and its singles "Love Story" and "You Belong with Me" catapulted her to
prominence. Speak Now (2010) incorporated rock influences, while Red (2012) experimented with
electronic elements and featured Swift's first Billboard Hot 100 number-one song, "We Are
Never Ever Getting Back Together". She forwent her country image with 1989 (2014), a synth-pop
album supported by the chart-topping songs "Shake It Off", "Blank Space", and "Bad Blood".
Media scrutiny inspired the hip-hop-flavored Reputation (2017) and its number-one single "Look
What You Made Me Do". Signing a new contract with Republic Records in 2018, Swift released her
seventh album, Lover (2019), and the autobiographical documentary Miss Americana (2020). She
embraced indie folk and alternative rock on her 2020 albums Folklore and Evermore, explored
chill-out styles on Midnights (2022), and re-recorded three of her first six albums as
"Taylor's Versions" following a dispute with Big Machine. The albums and their number-one
songs "Cardigan", "Willow", "All Too Well (10 Minute Version)" and "Anti-Hero" broke various
records. In 2023, Swift embarked on the Eras Tour, her most expansive concert tour. She has
also directed music videos and films such as All Too Well: The Short Film (2021) and played
supporting roles in others. Having sold over 200 million records globally, Swift is one of the
best-selling musicians, the most streamed woman on Spotify, and the only act to have five
albums open with over one million copies sold in the US. She has been featured in listicles
such as Rolling Stone's 100 Greatest Songwriters of All Time, Billboard's Greatest of All Time
Artists, the Time 100, and Forbes Celebrity 100. Among her accolades are 12 Grammy Awards,
including three Album of the Year wins; a Primetime Emmy Award; 40 American Music Awards; 29
Billboard Music Awards; 12 Country Music Association Awards; three IFPI Global Recording
Artist of the Year awards; and 98 Guinness World Records. Honored with titles such as Artist
of the Decade and Woman of the Decade, Swift is an advocate for artists' rights and women's
empowerment.
</div>
<template v-slot:footer>
<cl-button>footer</cl-button>
</template>
</cl-drawer>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const show = ref(false)
const width = ref(300)
const openDrawer = () => {
show.value = true
}
return {
show,
width,
openDrawer
}
}
})
</script>
自定义内容
使用自定义样式覆盖原有的样式
<template>
<div>
<cl-button @click="openDrawer" type="primary" style="margin-top: 10px">点击打开抽屉</cl-button>
<cl-drawer
v-model:show="show"
:headerStyle="headerStyle"
:bodyStyle="bodyStyle"
:footerStyle="footerStyle"
>
<template #header>
<span>标题插槽</span>
</template>
<p style="margin: 0">默认插槽,展示抽屉的内容</p>
<template #footer>
<cl-button>取消</cl-button>
<cl-button type="primary">确认</cl-button>
</template>
</cl-drawer>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const show = ref(false)
const headerStyle = {
height: '100px',
background: '#abc5a8',
borderBottom: 'none'
}
const bodyStyle = {
padding: '0 10px',
background: '#cde1d4'
}
const footerStyle = {
height: '50px',
background: '#8ecfa6'
}
const openDrawer = () => {
show.value = true
}
return {
show,
headerStyle,
bodyStyle,
footerStyle,
openDrawer
}
}
})
</script>
API
drawer Props
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
show | boolean | false | 控制抽屉的打开 |
placement | left right top bottom | right | 抽屉从哪个方向弹出 |
width | string / number | - | 抽屉的宽度 |
height | string / number | - | 抽屉的高度 |
size | default large | default | 抽屉的宽度或者高度, 具体见示例 2 |
zIndex | number | - | 抽屉的层级 |
blockScroll | boolean | true | 抽屉打开时是否锁定页面的滚动 |
resizable | boolean | false | 抽屉是否可以拖动其边缘改变其宽高 |
to | string / HTMLElement | body | 抽屉放置的位置 |
showMask | boolean | true | 显示遮罩层 |
maskClosable | boolean | true | 点击遮罩关闭抽屉 |
onMaskClick | (e: MouseEvent) => void | - | 点击遮罩关闭弹窗后的回调函数 |
drawerStyle | string / object | - | 抽屉的样式 |
drawerClass | string | - | 抽屉样式类名 |
onAfterEnter | () => void | - | 抽屉打开后调用的回调函数 |
onAfterLeave | () => void | - | 抽屉关闭后调用的回调函数 |
title | string | - | 抽屉的标题,如果抽屉同时设置了 title 和 slots.header,以 title 优先 |
closable | boolean | true | 是否显示标题栏的 closeIcon |
headerStyle | string / object | - | 抽屉 Header 部分的样式 |
bodyStyle | string / object | - | 抽屉 body 部分的样式 |
footerStyle | string / object | - | 抽屉 footer 部分的样式 |
slots
name | 描述 |
---|---|
header | 自定义抽屉 header 部分,包含 close icon |
close-icon | 自定义关闭按钮 |
footer | 自定义抽屉 footer 部分 |
默认插槽 | 自定义抽屉 body 部分 |
dialog Events
事件 | 描述 | 回调参数 |
---|---|---|
update:show | 抽屉的状态更新时触发 | 更新后的状态 |
update:width | 抽屉宽度更新时触发 | 更新后的宽度,没有单位 |
update:height | 抽屉高度更新时触发 | 更新后的高度,没有单位 |