Skip to content

Drawer 抽屉

从屏幕边缘滑出的抽屉面板。

何时使用

  • 需要从屏幕边缘滑出展示更多内容时
  • 需要在不离开当前页面的情况下展示详细信息时
  • 需要展示表单、设置面板等辅助内容时

基础用法

最简单的用法,从右侧滑出抽屉。

vue
<template>
  <YcButton @click="visible = true">打开抽屉</YcButton>
  <YcDrawer v-model:visible="visible" title="抽屉标题">
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
</script>

位置设置

通过 placement 属性设置抽屉出现的位置。

vue
<template>
  <YcSpace>
    <YcButton @click="placement = 'left'">左侧</YcButton>
    <YcButton @click="placement = 'right'">右侧</YcButton>
    <YcButton @click="placement = 'top'">顶部</YcButton>
    <YcButton @click="placement = 'bottom'">底部</YcButton>
  </YcSpace>
  
  <YcDrawer 
    v-model:visible="visible" 
    :placement="placement"
    title="抽屉标题"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
const placement = ref('right');
</script>

尺寸设置

通过 widthheight 属性设置抽屉尺寸。

vue
<template>
  <YcSpace>
    <YcButton @click="openDrawer('small')">小尺寸</YcButton>
    <YcButton @click="openDrawer('medium')">中等尺寸</YcButton>
    <YcButton @click="openDrawer('large')">大尺寸</YcButton>
  </YcSpace>
  
  <YcDrawer 
    v-model:visible="visible" 
    :width="drawerWidth"
    :height="drawerHeight"
    title="抽屉标题"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
const drawerWidth = ref(250);
const drawerHeight = ref(250);

const openDrawer = (size) => {
  if (size === 'small') {
    drawerWidth.value = 200;
    drawerHeight.value = 200;
  } else if (size === 'medium') {
    drawerWidth.value = 400;
    drawerHeight.value = 300;
  } else if (size === 'large') {
    drawerWidth.value = 600;
    drawerHeight.value = 400;
  }
  visible.value = true;
};
</script>

自定义头部

通过 header 插槽自定义头部内容。

vue
<template>
  <YcButton @click="visible = true">打开抽屉</YcButton>
  <YcDrawer v-model:visible="visible">
    <template #header>
      <div style="display: flex; align-items: center; gap: 8px;">
        <YcIcon-settings style="color: #1890ff;" />
        <span>设置面板</span>
        <YcTag color="blue">新</YcTag>
      </div>
    </template>
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
</script>

自定义底部

通过 footer 插槽自定义底部内容。

vue
<template>
  <YcButton @click="visible = true">打开抽屉</YcButton>
  <YcDrawer v-model:visible="visible" title="抽屉标题">
    <p>抽屉内容</p>
    <template #footer>
      <YcSpace>
        <YcButton @click="visible = false">关闭</YcButton>
        <YcButton type="primary" @click="handleSave">保存</YcButton>
        <YcButton type="primary" @click="handleSaveAndClose">保存并关闭</YcButton>
      </YcSpace>
    </template>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);

const handleSave = () => {
  console.log('保存数据');
};

const handleSaveAndClose = () => {
  handleSave();
  visible.value = false;
};
</script>

隐藏头部或底部

通过 headerfooter 属性控制头部和底部的显示。

vue
<template>
  <YcSpace>
    <YcButton @click="openDrawer(true, true)">显示头部和底部</YcButton>
    <YcButton @click="openDrawer(false, true)">隐藏头部</YcButton>
    <YcButton @click="openDrawer(true, false)">隐藏底部</YcButton>
    <YcButton @click="openDrawer(false, false)">隐藏头部和底部</YcButton>
  </YcSpace>
  
  <YcDrawer 
    v-model:visible="visible" 
    :header="showHeader"
    :footer="showFooter"
    title="抽屉标题"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
const showHeader = ref(true);
const showFooter = ref(true);

const openDrawer = (header, footer) => {
  showHeader.value = header;
  showFooter.value = footer;
  visible.value = true;
};
</script>

自定义按钮

通过 okButtonPropscancelButtonProps 自定义按钮属性。

vue
<template>
  <YcButton @click="visible = true">打开抽屉</YcButton>
  <YcDrawer 
    v-model:visible="visible" 
    title="抽屉标题"
    :ok-button-props="{ type: 'primary', danger: true }"
    :cancel-button-props="{ type: 'dashed' }"
    ok-text="删除"
    cancel-text="取消"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
</script>

加载状态

通过 okLoading 属性显示确认按钮的加载状态。

vue
<template>
  <YcButton @click="visible = true">打开抽屉</YcButton>
  <YcDrawer 
    v-model:visible="visible" 
    title="抽屉标题"
    :ok-loading="loading"
    @ok="handleOk"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
const loading = ref(false);

const handleOk = async () => {
  loading.value = true;
  try {
    await new Promise(resolve => setTimeout(resolve, 2000));
    console.log('操作完成');
    visible.value = false;
  } finally {
    loading.value = false;
  }
};
</script>

遮罩层设置

通过 maskmaskClosable 属性控制遮罩层。

vue
<template>
  <YcSpace>
    <YcButton @click="openDrawer(true, true)">有遮罩,可点击关闭</YcButton>
    <YcButton @click="openDrawer(true, false)">有遮罩,不可点击关闭</YcButton>
    <YcButton @click="openDrawer(false, false)">无遮罩</YcButton>
  </YcSpace>
  
  <YcDrawer 
    v-model:visible="visible" 
    title="抽屉标题"
    :mask="showMask"
    :mask-closable="maskClosable"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
const showMask = ref(true);
const maskClosable = ref(true);

const openDrawer = (mask, closable) => {
  showMask.value = mask;
  maskClosable.value = closable;
  visible.value = true;
};
</script>

关闭按钮设置

通过 closable 属性控制关闭按钮的显示。

vue
<template>
  <YcSpace>
    <YcButton @click="openDrawer(true)">显示关闭按钮</YcButton>
    <YcButton @click="openDrawer(false)">隐藏关闭按钮</YcButton>
  </YcSpace>
  
  <YcDrawer 
    v-model:visible="visible" 
    title="抽屉标题"
    :closable="showCloseButton"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
const showCloseButton = ref(true);

const openDrawer = (closable) => {
  showCloseButton.value = closable;
  visible.value = true;
};
</script>

服务调用

通过 DrawerService 以服务方式调用抽屉。

vue
<template>
  <YcButton @click="openDrawer">服务方式打开抽屉</YcButton>
</template>

<script setup>
import { DrawerService } from 'yc-design-vue';

const openDrawer = () => {
  DrawerService.open({
    title: '服务抽屉',
    content: '这是通过服务方式打开的抽屉',
    width: 400,
    onOk: () => {
      console.log('确认操作');
    },
    onCancel: () => {
      console.log('取消操作');
    }
  });
};
</script>

事件处理

监听抽屉的各种事件。

vue
<template>
  <YcButton @click="visible = true">打开抽屉</YcButton>
  <YcDrawer 
    v-model:visible="visible" 
    title="抽屉标题"
    @before-open="onBeforeOpen"
    @open="onOpen"
    @before-close="onBeforeClose"
    @close="onClose"
    @ok="onOk"
    @cancel="onCancel"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);

const onBeforeOpen = () => {
  console.log('即将打开');
};

const onOpen = () => {
  console.log('已打开');
};

const onBeforeClose = () => {
  console.log('即将关闭');
};

const onClose = () => {
  console.log('已关闭');
};

const onOk = () => {
  console.log('确认操作');
  visible.value = false;
};

const onCancel = () => {
  console.log('取消操作');
  visible.value = false;
};
</script>

自定义样式

通过 drawerStyle 属性自定义抽屉样式。

vue
<template>
  <YcButton @click="visible = true">打开抽屉</YcButton>
  <YcDrawer 
    v-model:visible="visible" 
    title="抽屉标题"
    :drawer-style="customStyle"
  >
    <p>抽屉内容</p>
  </YcDrawer>
</template>

<script setup>
import { ref } from 'vue';

const visible = ref(false);
const customStyle = {
  background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
  color: 'white'
};
</script>

完整示例

一个完整的抽屉使用示例。

vue
<template>
  <div class="page">
    <YcButton type="primary" @click="openUserDrawer">编辑用户信息</YcButton>
    
    <YcDrawer 
      v-model:visible="userDrawerVisible" 
      title="用户信息编辑"
      placement="right"
      width="500"
      :ok-loading="saving"
      @ok="saveUserInfo"
    >
      <YcForm layout="vertical">
        <YcFormItem label="用户名">
          <YcInput v-model="userForm.username" placeholder="请输入用户名" />
        </YcFormItem>
        
        <YcFormItem label="邮箱">
          <YcInput v-model="userForm.email" placeholder="请输入邮箱" />
        </YcFormItem>
        
        <YcFormItem label="手机号">
          <YcInput v-model="userForm.phone" placeholder="请输入手机号" />
        </YcFormItem>
        
        <YcFormItem label="地址">
          <YcTextarea v-model="userForm.address" placeholder="请输入地址" />
        </YcFormItem>
      </YcForm>
    </YcDrawer>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue';

const userDrawerVisible = ref(false);
const saving = ref(false);

const userForm = reactive({
  username: '',
  email: '',
  phone: '',
  address: ''
});

const openUserDrawer = () => {
  // 模拟加载用户数据
  userForm.username = '张三';
  userForm.email = 'zhangsan@example.com';
  userForm.phone = '13800138000';
  userForm.address = '北京市朝阳区';
  userDrawerVisible.value = true;
};

const saveUserInfo = async () => {
  saving.value = true;
  try {
    await new Promise(resolve => setTimeout(resolve, 1000));
    console.log('保存用户信息:', userForm);
    userDrawerVisible.value = false;
  } finally {
    saving.value = false;
  }
};
</script>

<style scoped>
.page {
  padding: 24px;
}
</style>

API

Props

参数说明类型默认值
visible是否可见boolean-
defaultVisible默认是否可见booleanfalse
placement抽屉位置DrawerPlacement'right'
title标题string''
mask是否显示遮罩booleantrue
maskClosable点击遮罩是否关闭booleantrue
closable是否显示关闭按钮booleantrue
okText确认按钮文字string'确认'
cancelText取消按钮文字string'取消'
okLoading确认按钮加载状态booleanfalse
okButtonProps确认按钮属性ButtonProps{}
cancelButtonProps取消按钮属性ButtonProps{}
unmountOnClose关闭时是否销毁子元素booleanfalse
width宽度number | string250
height高度number | string250
popupContainer弹窗挂载容器PopupContainer-
drawerStyle抽屉样式CSSProperties{}
escToClose按ESC键是否关闭booleantrue
renderToBody是否渲染到bodybooleantrue
header是否显示头部booleantrue
footer是否显示底部booleantrue
hideCancel是否隐藏取消按钮booleanfalse
onBeforeCancel取消前回调OnBeforeCancel-
onBeforeOk确认前回调OnBeforeOk-

Events

事件名说明回调参数
update:visible可见性变化时触发(value: boolean)
ok点击确认按钮时触发-
cancel点击取消按钮时触发(event: MouseEvent | KeyboardEvent)
before-open打开前触发-
open打开后触发-
before-close关闭前触发-
close关闭后触发-

Slots

插槽名说明
default抽屉内容
header自定义头部
footer自定义底部
title自定义标题

Types

typescript
type DrawerPlacement = 'right' | 'left' | 'top' | 'bottom';

注意事项

  1. 抽屉组件支持四个方向的滑出
  2. 宽度和高度会根据位置自动调整
  3. 可以通过服务方式调用,无需在模板中声明
  4. 支持键盘ESC键关闭

样式定制

组件提供了多个样式类,可以通过 CSS 进行定制:

css
.yc-drawer-wrapper {
  /* 抽屉包装器 */
}

.yc-drawer-mask {
  /* 遮罩层 */
}

.yc-drawer-container {
  /* 抽屉容器 */
}

.yc-drawer-header {
  /* 抽屉头部 */
}

.yc-drawer-body {
  /* 抽屉内容 */
}

.yc-drawer-footer {
  /* 抽屉底部 */
}

Released under the MIT License.