使用 HTMX( 以及 ASP. NET 核心) 显示通缩和互换内容 (中文 (Chinese Simplified))

使用 HTMX( 以及 ASP. NET 核心) 显示通缩和互换内容

Comments

NOTE: Apart from English (and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.

Saturday, 12 April 2025

//

Less than a minute

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

HTMX是一个伟大的图书馆,可以使您的网络应用程序更具活力和响应性。 我将教你们如何使用HTMX在页面上展示敬酒通知和互换内容。

标准 HTMX 中的“限制”之一(即: 非 OOB 互换通常只有从后端交换的单部分内容。 然而,通过使用 HX-Trigger 头头和一个小刺绣。

注:您可以使用 hx-swap-oob 转换两个不同的 内容内容内容 元素,但这个元素比较复杂, 做一些 JavaScripty 的东西并不容易使用。

东 多

我一直在使用这个简单的吐吐司通知系统的变种 暂时的.. 这是一个简单的函数, 需要信息、 持续时间和输入( 成功、 错误、 警告) 并在页面上显示敬酒通知 。

这个“ 最新版本” 围绕图标、 动画等等,

Javastrash 标注

// 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 片段, 我定义在 _布局. cshtml 文件( 使用我首选的尾风 CSS & DaisiUI) 。 注意结尾处的“阶级保护区块”。 这是一个小把戏,以确保在最后的 HTML 输出中保存分类 。 这真的是为了我的尾风布局,我只看一眼 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>

反尾风

这里我定义了“ 树木摇晃” 的文件, 并定义了吐司使用的一些动画类 。

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>

或者您可以在请求后的事件中定义它 。 所以,你做一些事情 然后它触发了一个新的事件。

<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>

如果你只想做点什么 那就表明已经做了 但我想换掉一些内容 举杯

            Response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
            {
                showToast = new
                {
                    toast = result.Message,
                    issuccess = result.Success
                }
            }));

如果我的触发器被点名 showToast 我传递信息 和成功旗。 所以我的联署材料 我为这次活动指定了一个活动听众 然后,这等于是说: 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.NET

我为什么要用这个? 在最近的一个工作项目中,我想对一个在表格上展示的用户采取一些行动。 我想展示一个敬酒会通知 并用新内容交换用户行的内容

userrow.png

正如你可以看到的,我有一个BUNCH按钮,它“做一些事情”给用户。 我想展示一个敬酒会通知 并用新内容交换用户行的内容

所以在我的控制下,我有一个简单的“开关”, 它使用动作名称, 做一些东西, 然后返回新的请求结果 。

    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 键和带有 toastissuccess 键。 缩略 toast 键是要在敬杯通知和 issuccess 键是显示该动作是否成功的布尔。

然后在 _Row 我部分拥有 HX (使用 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 但在这种情况下,我只用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 属性可在执行动作前显示确认对话框。 这是确保用户真正想要执行该动作的简单方法。 此用途 甜加速器2color 显示确认对话框。

如果您不这样做, HTMX 仍然有效, 但是它使用标准的浏览器“ confirm” 对话框, 这对用户来说有点困难 。

// 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 在页面上显示吐司通知和交换内容的简单方法 。 这是让您的网络应用程序更具活力和响应性的伟大方法。

logo

©2024 Scott Galloway