This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
以 HTMX @ (# 和 ASP+.@NET CoreQ)* 显示通缩及互换内容
Saturday, 12 April 2025
一. 导言导言 导言 导言 导言
HTMX 是一个伟大的图书馆, 能让您的网络应用程序更具活力和响应性@. @% 在此文章中, I,}#I'}将展示您如何使用HTMX 在页面上显示敬酒通知和互换内容_.}
标准 HTMX 中的“'”限制之一 非 OOB 互换) 是指您通常只有从后端交换的单部分内容@. 但是通过使用 HX-Trigger 头顶和小刺刀?
备注: 您可以使用 hx-swap-oob 转换两个不同的 内容内容内容 元素,但这种功能比较复杂,而且不容易用于做一些 JavaScripty stuff@. @%
东
I' 一直在使用这个简单的吐司通知系统的变体 暂时的. @ it'}这是一个简单的函数, 它可以接收消息@, @ 持续时间 @ MS K3 @ 并键入 @ I(_sucess{ ,} 错误 @ ,} 警告\ MSKO7} 并在页面上显示一个敬酒通知 @.}
@ ' @ latest version@ MS K1} 在图标周围有更多闪烁的动画等QZ...}
Java 标注
// HTMX toast notification
// Simple HTMX toast handler for use with hx-on::after-request
window.showToast = (message, duration = 3000, type = 'info') => {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toast-message');
const toastText = document.getElementById('toast-text');
const toastIcon = document.getElementById('toast-icon');
// Reset classes
toastMessage.className = 'alert shadow-lg gap-2 transition-all duration-300 ease-in-out cursor-pointer';
toastIcon.className = 'bx text-2xl';
// Add DaisyUI alert type
const alertClass = `alert-${type}`;
toastMessage.classList.add(alertClass);
// Add icon class
const iconMap = {
success: 'bx-check-circle',
error: 'bx-error-circle',
warning: 'bx-error',
info: 'bx-info-circle'
};
const iconClass = iconMap[type] || 'bx-bell';
toastIcon.classList.add(iconClass);
// Set the message
toastText.textContent = message;
// Add slide-in animation
toastMessage.classList.add('animate-slide-in');
toast.classList.remove('hidden');
// Allow click to dismiss
toastMessage.onclick = () => hideToast();
// Auto-dismiss
clearTimeout(window.toastTimeout);
window.toastTimeout = setTimeout(() => hideToast(), duration);
function hideToast() {
toastMessage.classList.remove('animate-slide-in');
toastMessage.classList.add('animate-fade-out');
toastMessage.onclick = null;
toastMessage.addEventListener('animationend', () => {
toast.classList.add('hidden');
toastMessage.classList.remove('animate-fade-out');
}, { once: true });
}
};
这使用一个小 HTML 片段, 我定义在 _使用我首选的尾风 CSS && DaisiU). 注意末端的 @ '\ 类保存区块 ' @ 这是小把戏, 以确保在 HTML 最后输出中保留分类@ MS K7} 这将真的用于我的尾风设置 cshtml.
<div
id="toast"
class="toast toast-bottom fixed z-50 hidden w-full md:w-auto max-w-sm right-4 bottom-4"
>
<div
id="toast-message"
class="alert shadow-lg gap-2 transition-all duration-300 ease-in-out cursor-pointer"
>
<i id="toast-icon" class="bx text-2xl"></i>
<span id="toast-text">Notification message</span>
</div>
</div>
<!-- class-preserving dummy block -->
<div class="hidden">
<div class="alert alert-success alert-error alert-warning alert-info"></div>
<i class="bx bx-check-circle bx-error-circle bx-error bx-info-circle bx-bell"></i>
<div class="animate-slide-in animate-fade-out"></div>
</div>
反尾风
在此我定义“ ' @ tree@ MSQK1shake @ MS K2}” 的文件, 并定义一些使用吐司的动画类@ MPK3
const defaultTheme = require("tailwindcss/defaultTheme");
module.exports = {
content: ["./Views/**/*.cshtml", "./Areas/**/*.cshtml"],
safelist: ["dark"],
darkMode: "class",
theme: {
extend: {
keyframes: {
'slide-in': {
'0%': { opacity: 0, transform: 'translateY(20px)' },
'100%': { opacity: 1, transform: 'translateY(0)' },
},
'fade-out': {
'0%': { opacity: 1 },
'100%': { opacity: 0 },
},
},
animation: {
'slide-in': 'slide-in 0.3s ease-out',
'fade-out': 'fade-out 0.5s ease-in forwards',
},
},
plugins: [require("daisyui")],
};
触发
使这一切得以实现的秘密是利用 HTMX 触发信头功能.
现在,"'}(通常)你愿意 在您 html @ / 剃须刀代码中定义此值:
<div hx-get="/clicked" hx-trigger="click[ctrlKey]">Control Click Me</div>
或者您可以在请求后的事件中定义它 @ . @ 所以做点什么, 然后触发新的事件@ MS K1} @
<button
hx-get="/api/do-something"
hx-swap="none"
hx-on::afterRequest="window.showToast('API call complete!', 3000, 'success')"
class="btn btn-primary"
>
Do Something
</button>
如果您想做点什么来表示它已经做了 @'_%s done@'}但对于我来说,我想交换一些内容 并展示一个祝酒词#.}
Response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
{
showToast = new
{
toast = result.Message,
issuccess = result.Success
}
}));
如果我的扳机被点名 showToast 并且我传递了一个信息,一个成功的旗子. 所以我的联署材料JS 我定义了这次活动的活动听众 showToast 和成功标记中的传递
// Handles HX-Trigger: { "showToast": { "toast": "...", "issuccess": true } }
document.body.addEventListener("showToast", (event) => {
const { toast, issuccess } = event.detail || {};
const type = issuccess === false ? 'error' : 'success';
showToast(toast || 'Done!', 3000, type);
});
ASP=.网
那么为什么我在最近一个工程项目中使用这个“?”? 我想对在表格中显示的用户采取一些行动? “. ”我想展示敬酒通知,用新的内容来交换用户行的内容?“MS K2 ”

您可以看到我有一个 BUNCH 按钮, 它的“ ' @ do stuff@ MS K1 @ ” 到用户@ I.} 我想显示一个敬酒会通知并用新内容交换用户行的内容@.}
所以在我的控制下,我有一个简单的“' @switch@' ” 。 该动作将使用“ , 做一些事情”, 然后返回新的请求结果“ MPK3
private async Task ApplyAction(string email, string useraction)
{
if (!string.IsNullOrWhiteSpace(useraction) &&
Enum.TryParse<UserActionType>(useraction, true, out var parsedAction))
{
RequestResult result;
switch (parsedAction)
{
case UserActionType.FlipRoles:
result = await userActionService.FlipRestaurantPermissions(email);
break;
case UserActionType.UnflipRoles:
result = await userActionService.UnFlipRestaurantPermissions(email);
break;
case UserActionType.Enable2FA:
result = await userActionService.ToggleMFA(email, true);
break;
case UserActionType.Disable2FA:
result = await userActionService.ToggleMFA(email, false);
break;~~~~
case UserActionType.RevokeTokens:
result = await userActionService.RevokeTokens(email);
break;
case UserActionType.Lock:
result = await userActionService.Lock(email);
break;
case UserActionType.Unlock:
result = await userActionService.Unlock(email);
break;
case UserActionType.Nuke:
result = await userActionService.Nuke(email);
break;
case UserActionType.Disable:
result = await userActionService.DisableUser(email);
break;
case UserActionType.Enable:
result = await userActionService.EnableUser(email);
break;
case UserActionType.ResetPassword:
result = await userActionService.ChangePassword(email);
break;
case UserActionType.SendResetEmail:
result = await userActionService.SendResetEmail(email);
break;
default:
result = new RequestResult(false, "Unknown action");
break;
}
Response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
{
showToast = new
{
toast = result.Message,
issuccess = result.Success
}
}));
}
}
你可以看到我还附上了 HX-Trigger 这是 JSON 对象, 带有 showToast 键和带有 toast 和 issuccess 关键“.” toast 键是要在敬杯通知和 issuccess 键是一个布尔,显示该动作是否成功@. @%
然后在 _Row 使用 HTMX . @Net@)}属性触发动作“.}”
<!-- Revoke Login Tokens -->
<button class="btn btn-xs btn-error border whitespace-normal text-wrap tooltip tooltip-left" data-tip="Revoke login tokens"
hx-get hx-indicator="#loading-modal" hx-target="closest tr" hx-swap="outerHTML"
hx-action="Row" hx-controller="Users"
hx-route-email="@user.Email" hx-route-useraction="@UserActionType.RevokeTokens"
hx-confirm="Are you sure you want to revoke the login tokens for this user?">
<i class="bx bx-power-off"></i> Revoke
</button>
你可以看到我用的是目标 closest tr 将整个行替换为新内容@.}这是更新该行内容的简单方法,无需做整页刷新 *\ .
部分视图
这是一个非常简单和伟大的技术 用于ASP'.NET核心与HTMX.}
您可以选择使用 HTMX @ .@ Nets 请求@. @IsHtmx @`}但在此情况下,我只使用 HTMX 的回调@ .#%
[Route("row")]
public async Task<IActionResult> Row(string email, string? useraction = null)
{
if(!string.IsNullOrEmpty(useraction))
await ApplyAction(email, useraction);
var userRow = await userViewService.GetSingleUserViewModel(email);
return PartialView("_Row", userRow);
}
在这种情况下,部分意见 _Row 是一个简单的表格行,带有用户信息和用于执行动作的按钮@.
额外的HTMX特性
我还使用一些更多的 HTMX 功能,使用户的经验更好一点。
正在装入
我也用一个简单的 loading modal 这是向用户显示背景中正在发生某事的简单方式 @.}
<div id="loading-modal" class="modal htmx-indicator">
<div
class="modal-box flex flex-col items-center justify-center bg-base-200 border border-base-300 shadow-xl rounded-xl text-base-content dark text-center ">
<div class="flex flex-col items-center space-y-4">
<h2 class="text-lg font-semibold tracking-wide">Loading...</h2>
<span class="loading loading-dots loading-xl text-4xl text-stone-200"></span>
</div>
</div>
</div>
确认
我也使用 hx-confirm 执行动作前显示确认对话框的属性@. @% 这是确保用户真正想要执行动作的简单方式 @.}此用途 SweetAlert 2 * 甜蜜的阿勒特* MSK0* 显示确认对话框@. @%
如果您现在做这个“,” HTMX 仍然有效, 但是它使用标准浏览器 @ '\confirmation'}对话框, 这对用户来说可能有点难用@ MS K4}
// HTMX confirm with SweetAlert2
window.addEventListener('htmx:confirm', (e) => {
const message = e.detail.question;
if (!message) return;
e.preventDefault();
Swal.fire({
title: 'Please confirm',
text: message,
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Yes',
cancelButtonText: 'Cancel',
theme: 'dark',
}).then(({ isConfirmed }) => {
if (isConfirmed) e.detail.issueRequest(true);
});
});
在结论中的结论
这是使用 HTMX 在页面上显示吐司通知和互换内容的简单方法 @.}这是让您的网络应用程序更具动态性和响应性@ .