Skip to content

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

名称类型默认值描述
showbooleanfalse控制抽屉的打开
placementleft right top bottomright抽屉从哪个方向弹出
widthstring / number-抽屉的宽度
heightstring / number-抽屉的高度
sizedefault largedefault抽屉的宽度或者高度, 具体见示例 2
zIndexnumber-抽屉的层级
blockScrollbooleantrue抽屉打开时是否锁定页面的滚动
resizablebooleanfalse抽屉是否可以拖动其边缘改变其宽高
tostring / HTMLElementbody抽屉放置的位置
showMaskbooleantrue显示遮罩层
maskClosablebooleantrue点击遮罩关闭抽屉
onMaskClick(e: MouseEvent) => void-点击遮罩关闭弹窗后的回调函数
drawerStylestring / object-抽屉的样式
drawerClassstring-抽屉样式类名
onAfterEnter() => void-抽屉打开后调用的回调函数
onAfterLeave() => void-抽屉关闭后调用的回调函数
titlestring-抽屉的标题,如果抽屉同时设置了 title 和 slots.header,以 title 优先
closablebooleantrue是否显示标题栏的 closeIcon
headerStylestring / object-抽屉 Header 部分的样式
bodyStylestring / object-抽屉 body 部分的样式
footerStylestring / object-抽屉 footer 部分的样式

slots

name描述
header自定义抽屉 header 部分,包含 close icon
close-icon自定义关闭按钮
footer自定义抽屉 footer 部分
默认插槽自定义抽屉 body 部分

dialog Events

事件描述回调参数
update:show抽屉的状态更新时触发更新后的状态
update:width抽屉宽度更新时触发更新后的宽度,没有单位
update:height抽屉高度更新时触发更新后的高度,没有单位