开发一个使用优雅的对话框

旧版彩票365下载 2025-10-26 22:32:42 admin

# 开发一个使用优雅的对话框 对话框是一个十分常用的组件,它在与用户交互时,可以提供有效信息,并帮助用户正确做出决策。在这一节中,我们将学习如何使用对话框组件。

# 对话框的需求 那么,我们首先来看一下对话框的需求。对话框的需求主要包括以下几个方面:

对话框的标题区 对话框的内容区 对话框的操作区 对话框的样式大体上都是分成三大块,这个不会变。我希望从使用上来说,对话框可以更加简洁。

# 对话框的实现 因为我们已经实现了 modal,所以对话框直接继承 modal 即可。

export interface DialogProps extends ModalProps {

/**

* 是否显示

*/

visible?: boolean;

/**

* 标题

*/

title?: string;

/**

* 是否显示关闭按钮

*/

showClose?: boolean;

/**

* 宽度

*/

width?: string | number;

/**

* 顶部距离(当 vertical 不为 center 时生效)

*/

top?: string | number;

/**

* 内容是否水平居中

*/

center?: boolean;

/**

* 垂直对齐方式

*/

vertical?: VerticalAlign;

/**

* 固定内容高度

*/

bodyHeight?: string | number;

/**

* 是否显示底部

*/

showFooter?: boolean;

/**

* 自定义类名

*/

customClass?: string;

}

12345678910111213141516171819202122232425262728293031323334353637383940414243有了 props,我们就可以开始实现对话框了。

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130这里,我特意处理了一下样式,我是希望对话框可以根据用户需求,可以自动东计算当前位置,包括整体 body 的高度。但这只是简单的大体处理了一下,可以保证对话框可以在页面内,超高时会自动出现滚动条。

当然,还有样式,这里就不写了,有兴趣的朋友可以去看源码,或者自己尝试写一下,很简单。

# 对话框的使用需求 有了对话框组件,接下来就是使用了。传统的使用来说,以 element 为例:

在 template 中写好对话框的内容 在 script 中写好对话框的逻辑 在 style 中写好对话框的样式

1234567891011121314151617181920212223这样的使用方式,对于开发者来说,是比较繁琐的。我们希望对话框的使用方式更加简洁。

showDialog() {

this.$dialog(DialogComponent, {

// ...对话框的参数

});

}

12345这里,我们直接用函数,创建了一个对话框,传递一个对话框组件,保持了自定义内容的效果,同时可以使用不同参数进行个性化。

当时,我认为这还不够好,因为对于回调来说,这不够友好。这里有两种回调的方式:

参数回调。这种更加自由,允许用户任意使用任何回调,毕竟参数是自己写的。 通过 Promise 回调。我更喜欢这种编写方式。但是它有一些约束。下面我们来实现这种方式。 # 对话框的回调 首先,我们需要实现创建对话框的方法:

export function createDialog(

content: typeof XDialogInstance,

options: DialogOptions = {}

): DialogReturn {

const { ...dialogProps } = options;

const id = "x-dialog-" + generateId(12);

// 创建容器

const container = document.createElement("div");

container.id = id;

document.body.appendChild(container);

// 这就是实现回调的关键

let resolvePromise: (value: any) => void;

let rejectPromise: (reason?: any) => void;

// 创建包装组件

const visible = ref(false);

const Wrapper = defineComponent({

setup() {

// 处理确认

const handleConfirm = (value?: any) => {

visible.value = false;

resolvePromise(value);

};

// 处理取消

const handleCancel = (reason?: any) => {

visible.value = false;

rejectPromise(reason);

};

// 处理关闭

const handleClose = () => {

visible.value = false;

rejectPromise("closed");

};

return () =>

h(content, {

dialogProps,

visible: visible.value,

"onUpdate:visible": (val: boolean) => {

visible.value = val;

if (!val) handleClose();

},

// 我们会发现在对话框里,需要提供这三个方法

onConfirm: handleConfirm,

onCancel: handleCancel,

onClose: handleClose

});

}

});

const dialogInstance: DialogInstance = {

// 提供手动关闭方法

close: (value?: any) => {

resolvePromise(value);

},

// 提供更新配置方法

update: (newOptions: DialogOptions) => {

Object.assign(options, newOptions);

}

};

// 创建Promise

const promise = new Promise((resolve, reject) => {

resolvePromise = resolve;

rejectPromise = reject;

// 渲染对话框

render(h(Wrapper), container);

visible.value = true;

}) as DialogReturn;

// 附加实例方法到Promise

promise.instance = dialogInstance;

return promise;

}

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081仔细查看,这里有几个细节:

最后返回的一定是一个 Promise,或者 PromiseLike 对象,这样才可以使用 then 实现我们期望的回调。 创建组件时,没有使用常用的 createApp,而是直接使用 render,这样可以保证对话框的实例与当前页面实例不会有冲突。 为了实现回调,我们需要提供三个方法:onConfirm、onCancel、onClose,这三个方法是对话框的核心方法。 当然,这里没有实现对话框的销毁,这个可以根据实际情况来实现。

# 如何使用回调 为了使用,我们对即将创建的对话框组件需要有一些约定:

组件应当使用我们提供的 XDialog 作为根组件 组件中务必提供 onConfirm、onCancel、onClose 三个方法中的一个或多个,这个根据使用 then(需要 onConfirm)、catch(需要 onCancel/onClose) 来决定。