Skip to content
本页目录

Drawer 抽屉

主要用于当前页面的操作结果需要承载的内容较多的场景使用抽屉组件,逻辑和 Modal 类似

组件注册

js
import { FDrawer } from '@fesjs/fes-design';

app.use(FDrawer);

代码演示

基础用法

play
<template>
    <FSpace>
        <FButton @click="show[0] = true">常规</FButton>
        <FButton class="ml-10" @click="show[1] = true">没有标题</FButton>
        <FButton class="ml-10" @click="show[2] = true">不显示关闭</FButton>
        <FButton class="ml-10" @click="show[3] = true">没有遮罩</FButton>
        <FButton class="ml-10" @click="show[4] = true">显示页脚</FButton>
        <FDrawer
            v-model:show="show[0]"
            title="常规"
            displayDirective="if"
            @ok="show[0] = false"
        >
            <div>我是内容...</div>
            <div>我是内容...</div>
            <div>我是内容...</div>
        </FDrawer>
        <FDrawer v-model:show="show[1]" @ok="show[1] = true">
            <FAlert
                style="margin-bottom: 10px"
                type="info"
                message="没有标题..."
            />
            <div>没有标题...</div>
            <div>没有标题...</div>
        </FDrawer>

        <FDrawer
            v-model:show="show[2]"
            title="不显示关闭"
            :closable="false"
            @ok="show[2] = false"
        >
            <div>我是内容...</div>
            <div>我是内容...</div>
            <div>我是内容...</div>
        </FDrawer>

        <FDrawer
            v-model:show="show[3]"
            title="没有遮罩"
            :mask="false"
            @ok="show[3] = false"
        >
            <div>我是内容...</div>
            <div>我是内容...</div>
            <div>我是内容...</div>
        </FDrawer>
        <FDrawer
            v-model:show="show[4]"
            title="显示页脚"
            :footer="true"
            displayDirective="if"
            @ok="show[4] = false"
        >
            <div style="height: 1000px">我是内容...</div>
            <div>我是内容...</div>
            <div>我是内容...</div>
        </FDrawer>
    </FSpace>
</template>

<script>
import { reactive } from 'vue';

export default {
    setup() {
        const show = reactive([]);
        return {
            show,
        };
    },
};
</script>

位置

自定义位置,点击触发按钮抽屉从相应的位置滑出,点击遮罩区关闭,默认是 right

play
<template>
    <FSpace>
        <FRadioGroup v-model="placement">
            <FRadio value="top">top</FRadio>
            <FRadio value="bottom">bottom</FRadio>
            <FRadio value="left">left</FRadio>
            <FRadio value="right">right</FRadio>
        </FRadioGroup>
    </FSpace>
    <FButton style="margin-top: 20px" @click="open">打开抽屉</FButton>
    <FDrawer
        v-model:show="show"
        title="这里是标题"
        :placement="placement"
        @ok="show = false"
    >
        <div>我是内容...</div>
        <div>我是内容...</div>
        <div>我是内容...</div>
    </FDrawer>
</template>

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

export default {
    setup() {
        const placement = ref('right');
        const show = ref(false);
        const open = () => {
            show.value = true;
        };
        return {
            placement,
            show,
            open,
        };
    },
};
</script>

拖拽

可设置宽度或者高度可拖拽,默认 resizable 是 false

play
<template>
    <FForm>
        <FFormItem label="位置:">
            <FRadioGroup v-model="placement">
                <FRadio value="top">top</FRadio>
                <FRadio value="bottom">bottom</FRadio>
                <FRadio value="left">left</FRadio>
                <FRadio value="right">right</FRadio>
            </FRadioGroup>
        </FFormItem>
    </FForm>

    <FDivider></FDivider>

    <FButton @click="open">打开抽屉</FButton>
    <FDrawer
        v-model:show="show"
        title="这里是标题"
        resizable
        :placement="placement"
        width="600px"
        @ok="show = false"
    >
        <div>我是内容...</div>
        <div>我是内容...</div>
        <div>我是内容...</div>
    </FDrawer>
</template>

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

export default {
    setup() {
        const show = ref(false);
        const placement = ref('right');

        const open = () => {
            show.value = true;
        };
        return {
            show,
            open,
            placement,
        };
    },
};
</script>

自定义头部

通过 slot title可以自定义页脚内容

play
<template>
    <FSpace>
        <FButton @click="show = true">自定义头部</FButton>
        <FDrawer v-model:show="show" title="这里是标题" @ok="show = false">
            <template #title>
                <div class="header">
                    <span style="margin-right: 8px">自定义头部标题</span>
                    <EditOutlined />
                </div>
            </template>
            <div>我是内容...</div>
            <div>我是内容...</div>
            <div>我是内容...</div>
        </FDrawer>
    </FSpace>
</template>

<script>
import { ref } from 'vue';
import { EditOutlined } from '@fesjs/fes-design/icon';

export default {
    components: {
        EditOutlined,
    },
    setup() {
        const show = ref(false);
        return {
            show,
        };
    },
};
</script>

<style scoped>
.header {
    display: flex;
    flex-direction: row;
    align-items: center;
}
</style>

自定义页脚

通过 slot footer可以自定义页脚内容

play
<template>
    <FSpace>
        <FButton @click="show = true">自定义页脚</FButton>
        <FDrawer
            v-model:show="show"
            title="这里是标题"
            :footer="true"
            displayDirective="if"
        >
            <div style="height: 1000px">我是内容...</div>
            <div>我是内容...</div>
            <div>我是内容...</div>
            <template #footer>
                <FSpace justify="end">
                    <FButton>取消</FButton>
                    <FButton type="primary">确认</FButton>
                </FSpace>
            </template>
        </FDrawer>
    </FSpace>
</template>

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

export default {
    setup() {
        const show = ref(false);
        return {
            show,
        };
    },
};
</script>

异步提交

针对抽屉确认提交操作。

play
<template>
    <FForm>
        <FFormItem label="是否展示取消按钮:">
            <FRadioGroup
                v-model="showCancel"
                :options="[
                    { label: '是(默认)', value: true },
                    { label: '', value: false },
                ]"
            />
        </FFormItem>
        <FFormItem label="是否显示底部分割线:">
            <FRadioGroup
                v-model="showFooterBorder"
                :options="[
                    { label: '', value: true },
                    { label: '否(默认)', value: false },
                ]"
            />
        </FFormItem>
    </FForm>

    <FDivider></FDivider>

    <FSpace>
        <FButton @click="() => (normalShow = true)">常规</FButton>
        <FButton @click="() => (customShow = true)">自定义页脚</FButton>
    </FSpace>

    <FDrawer
        v-model:show="normalShow"
        title="常规"
        displayDirective="if"
        :footer="true"
        :footerBorder="showFooterBorder"
        :okLoading="normalOkLoading"
        :okText="normalOkText"
        :showCancel="showCancel"
        @ok="() => handleNormalOk()"
        @cancel="normalShow = false"
    >
        <div style="height: 1000px">我是内容...</div>
        <div>我是内容...</div>
        <div>我是内容...</div>
    </FDrawer>

    <FDrawer
        v-model:show="customShow"
        displayDirective="if"
        :footer="true"
        :footerBorder="showFooterBorder"
        title="自定义页脚"
    >
        <div style="height: 1000px">我是内容...</div>
        <div>我是内容...</div>
        <div>我是内容...</div>
        <template #footer>
            <FSpace justify="end">
                <FButton
                    v-show="showCancel"
                    type="warning"
                    :loading="customCancelLoading"
                    @click="handleCustomCancel"
                >
                    {{ customCancelText }}
                </FButton>
                <FButton
                    type="primary"
                    :loading="customOkLoading"
                    @click="handleCustomOk"
                >
                    {{ customOkText }}
                </FButton>
            </FSpace>
        </template>
    </FDrawer>
</template>

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

function sleep(time) {
    return new Promise((resolve) => setTimeout(resolve, time));
}

function useDrawer() {
    const show = ref(false);
    const okLoading = ref(false);
    const cancelLoading = ref(false);
    const okText = ref('提交更新');
    const cancelText = ref('数据还原');

    const handleCancel = async () => {
        cancelLoading.value = true;
        cancelText.value = '3s后自动关闭';
        await sleep(3000);
        cancelLoading.value = false;
        show.value = false;
        await nextTick();
        cancelText.value = '数据还原';
    };
    const handleOk = async () => {
        okLoading.value = true;
        okText.value = '2s后自动关闭';
        await sleep(2000);
        okLoading.value = false;
        show.value = false;
        await nextTick();
        okText.value = '提交更新';
    };

    return {
        show,
        okLoading,
        cancelLoading,
        handleCancel,
        handleOk,
        okText,
        cancelText,
    };
}

export default {
    setup() {
        const showCancel = ref(true);
        const showFooterBorder = ref(true);

        const {
            show: normalShow,
            okLoading: normalOkLoading,
            handleOk: handleNormalOk,
            okText: normalOkText,
        } = useDrawer();

        const {
            show: customShow,
            cancelLoading: customCancelLoading,
            okLoading: customOkLoading,
            handleCancel: handleCustomCancel,
            handleOk: handleCustomOk,
            okText: customOkText,
            cancelText: customCancelText,
        } = useDrawer();

        return {
            showFooterBorder,

            normalShow,
            normalOkLoading,
            handleNormalOk,
            normalOkText,
            showCancel,

            customShow,
            customCancelLoading,
            customOkLoading,
            handleCustomCancel,
            handleCustomOk,
            customOkText,
            customCancelText,
        };
    },
};
</script>

Drawer Props

属性说明类型默认值
showv-model:show,是否显示抽屉Booleanfalse
displayDirective选择渲染使用的指令,if 对应 v-if,show 对应 v-show,使用 show 的时候不会被重置stringshow
closable是否显示右上角关闭图标Booleantrue
mask是否显示蒙层Booleantrue
maskClosable点击蒙层是否允许关闭Booleantrue
title标题String-
footer是否显示底部内容Booleanfalse
footerBorder是否显示底部分割线Booleanfalse
okText确认按钮文字String确定
okLoading确认按钮 Loading 状态Booleanfalse
showCancel是否展示取消按钮Booleantrue
cancelText取消按钮文字String取消
width宽度String/Number520
hight高度,在 placement 为 top 或 bottom 时使用String/Number520
placement抽屉方向'right''right' 、'bottom' 、 'left' 、 'right'
contentClass可用于设置内容的类名String-
getContainer指定 Drawer 挂载的 HTML 节点() => HTMLElement() => document.body
resizable是否支持宽度/高度可拖拽Booleanfalse

Drawer Event

事件名称说明回调参数
cancel点击遮罩层或右上角叉或取消按钮的回调event
ok点击确定回调event

Drawer Slots

名称说明
default模态框的内容
title模态框的标题
footer底部内容,一般是自定义按钮