自定义模态对话框

虽然htmx与CSS框架(如BootstrapUIKit)内置的对话框配合得很好,但htmx也能轻松地从头构建模态对话框。这里是一个快速示例,展示一种构建方式。

点击这里查看最终结果的演示:

高层计划

我们将创建一个按钮,用于从服务器加载远程内容,然后在模态对话框中显示。模态内容将被添加到<body>元素的末尾,位于名为#modal的div中。

在这个演示中,我们将在CSS中定义一些精美的动画,然后使用Hyperscript在用户完成操作后从DOM中移除模态框。Hyperscript不是htmx必需的,但两者设计为协同工作,且比JavaScript更适合编写异步和事件驱动的代码,因此我们在此示例中选择了它。

主页面HTML

<button class="btn primary" hx-get="/modal" hx-target="body" hx-swap="beforeend">打开模态框</button>
<div id="modal" _="on closeModal add .closing then wait for animationend then remove me">
	<div class="modal-underlay" _="on click trigger closeModal"></div>
	<div class="modal-content">
		<h1>模态对话框</h1>
		这是模态内容。
		您可以在此放置任何内容,如文本、表单或图像。
		<br>
		<br>
		<button class="btn danger" _="on click trigger closeModal">关闭</button>
	</div>
</div>

自定义样式表

/***** 模态对话框 ****/
#modal {
	/* 底层覆盖整个屏幕 */
	position: fixed;
	top:0px;
	bottom: 0px;
	left:0px;
	right:0px;
	background-color:rgba(0,0,0,0.5);
	z-index:1000;

	/* 使用Flexbox垂直水平居中.modal-content */
	display:flex;
	flex-direction:column;
	align-items:center;

	/* 打开时动画效果 */
	animation-name: fadeIn;
	animation-duration:150ms;
	animation-timing-function: ease;
}

#modal > .modal-underlay {
	/* 底层占据整个视口,仅在需要点击关闭弹窗时使用 */
	position: absolute;
	z-index: -1;
	top:0px;
	bottom:0px;
	left: 0px;
	right: 0px;
}

#modal > .modal-content {
	/* 将可见对话框定位在窗口顶部附近 */
	margin-top:10vh;

	/* 可见对话框尺寸 */
	width:80%;
	max-width:600px;

	/* 可见对话框显示属性 */
	border:solid 1px #999;
	border-radius:8px;
	box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.3);
	background-color:white;
	padding:20px;

	/* 打开时动画效果 */
	animation-name:zoomIn;
	animation-duration:150ms;
	animation-timing-function: ease;
}

#modal.closing {
	/* 关闭时动画效果 */
	animation-name: fadeOut;
	animation-duration:150ms;
	animation-timing-function: ease;
}

#modal.closing > .modal-content {
	/* 关闭时动画效果 */
	animation-name: zoomOut;
	animation-duration:150ms;
	animation-timing-function: ease;
}

@keyframes fadeIn {
	0% {opacity: 0;}
	100% {opacity: 1;}
}

@keyframes fadeOut {
	0% {opacity: 1;}
	100% {opacity: 0;}
}

@keyframes zoomIn {
	0% {transform: scale(0.9);}
	100% {transform: scale(1);}
}

@keyframes zoomOut {
	0% {transform: scale(1);}
	100% {transform: scale(0.9);}
}