以 HTMX @ (# 和 ASP+.@NET CoreQ)* 显示通缩及互换内容 (中文 (Chinese Simplified))

以 HTMX @ (# 和 ASP+.@NET CoreQ)* 显示通缩及互换内容

Saturday, 12 April 2025

//

6 minute read

一. 导言导言 导言 导言 导言

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 ”

userrow.png

您可以看到我有一个 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 在页面上显示吐司通知和互换内容的简单方法 @.}这是让您的网络应用程序更具动态性和响应性@ .

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.