Back to "ASP.NET 核心的Alpine.js和HTMX启用的 ASP.NET 标签助手"

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

Alpine.js ASP.NET Core HTMX Javascript

ASP.NET 核心的Alpine.js和HTMX启用的 ASP.NET 标签助手

Wednesday, 23 April 2025

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

简而言之,我需要一个工程项目 来“清除” URL 参数的能力 从 URL 中清除 URL 参数 。 当您有一个带多个参数的 URL 时, 并且您想要删除一个或多个参数( 例如搜索过滤器), 此选项是有用的 。

问题

我目前的计划使用旧式查询串(这是一个行政管理网站, 所以我最后有了像这样的 URL:

/products?category=electronics&search=wireless+headphones&sort=price_desc&inStock=true&page=3

现在这些可以随每页而变化, 这样我就可以在网页 URL 上有一个BUNCH, 我需要能够清除它们, 而不用写一堆锅炉板来完成它。

您可以将此作为您使用的任何输入控制的一部分, 例如在每个复选框旁边( 或一个花哨占位符样式清晰的图标), 但是您也可以使用此技术来控制 。 然而,在这种情况下,我想做两件事:

  1. 能够清除指定参数
  2. 能够清除参数列表 。
  3. 能够清除所有参数
  4. 和HTMX一起寄回去
  5. 使用我的装货指示器 我的装货指示器.

解决方案

在我的项目中,我已经使用

  • HTMX
  • 阿尔卑山
  • ASP.NET核心
  • 尾风CSS
  • DisacyUI 调音界面

所以,我的解决方案是 专注于使用这些 以获得一个漂亮的 功能性解决方案 与最小代码。

标签辅助工具

我的TagHeelfer很简单 我所做的就是创造 <a> 带有几个属性的标记, 我稍后会传递到阿尔卑斯山模块, 我们就结束了 。

[HtmlTargetElement("clear-param")]
public class ClearParamTagHelper : TagHelper
{
    [HtmlAttributeName("name")]
    public string Name { get; set; }
    
    [HtmlAttributeName("all")]
    public bool All { get; set; }= false;
    
    [HtmlAttributeName("target")]
    public string Target { get; set; } = "#page-content";

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "a";
        output.Attributes.SetAttribute("x-data", "window.queryParamClearer({})");

        if (All)
        {
        output.Attributes.SetAttribute("x-all", All);
        }
        else
        {
            output.Attributes.SetAttribute("x-param", Name);
        }
        output.Attributes.SetAttribute("data-target", Target);
        output.Attributes.SetAttribute("x-on:click.prevent", "clearParam($event)");
        output.Content.SetHtmlContent(@"
            <div class='w-6 h-6 flex items-center justify-center bg-red-600 text-white rounded-full'>
                <i class='bx bx-x text-lg'></i>
            </div>");
    }
}

参数参数

使用这个看起来像这个, 首先是“ 清除所有参数 ” 。 所以我就看一看 Context.Request.Query 如果有任何参数的话 我做一个小的 x 图标,让用户清除所有参数。


@if(Context.Request.Query.Any())
{
<label class="param-label">
    <clear-param all="true"></clear-param>
    clear all
</label>
}
</div>

作为指定参数的替代参数,我可以做到这一点


<div class="param-label">
    <clear-param name="myParam"></clear-param>
    <p>My Param: @Model.MyParam</p>
</div>

这当然能清除单一参数。

甚至


<div class="param-label">
    <clear-param name="myParam1,myParam2,myParam3"></clear-param>
    <p>My Param: @Model.MyParam1</p>
    <p>My Param: @Model.MyParam2</p>
    <p>My Param: @Model.MyParam3</p>
</div>

这将从字符串中清除所有命名参数 。

缩略 target 属性属性

YOu还可以选择通过 target 属性将用作 hx-target 属性。 如果您想要用新内容更新页面的特定部分, 此选项是有用的 。


<div class="param-label">
    <clear-param name="myParam" target="#my-thing"></clear-param>
    <p>My Param: @Model.MyParam</p>
</div>

以我的情况(因为我写了),我把目标违约到我的 #page-content (div) div.

    [HtmlAttributeName("target")]
    public string Target { get; set; } = "#page-content";

结果

这些结果产生了以下HTML:

  • 所有人: 因此,我们得到了 HTML 与 x-all 属性和无属性 x-param 属性。
<a x-data="window.queryParamClearer({})" x-all="True" data-target="#page-content" x-on:click.prevent="clearParam($event)">
    <div class="w-6 h-6 flex items-center justify-center bg-red-600 text-white rounded-full">
        <i class="bx bx-x text-lg"></i>
    </div>
</a>

  • 单身单身单身 我们得到HTML与 x-param 属性和无属性 x-all 属性。
<a x-data="window.queryParamClearer({})" x-param="myParam" data-target="#page-content" x-on:click.prevent="clearParam($event)">
    <div class="w-6 h-6 flex items-center justify-center bg-red-600 text-white rounded-full">
        <i class="bx bx-x text-lg"></i>
    </div>
</a>
  • 多个 我们得到HTML与 x-param 带有逗号分隔字符串和无字符串的属性的逗号分隔字符串 x-all 属性。
<a x-data="window.queryParamClearer({})" x-param="myParam1,myParam2,myParam3" data-target="#page-content" x-on:click.prevent="clearParam($event)">
    <div class="w-6 h-6 flex items-center justify-center bg-red-600 text-white rounded-full">
        <i class="bx bx-x text-lg"></i>
    </div>
</a>

每个高山都拥有两个高山的属性 x-datax-on:click.prevent 用于设置阿尔卑斯山模块,并调用函数来清除参数。

我们看看接下来会怎样...

阿尔卑斯山模块

当然,之所以能够做到这一点,是因为利用Alpine.js来配置我们的请求和用于执行请求的HTMX。

从下面的代码中可以看到 我有一个简单的模块 path 当前页面,然后使用 URL API 用于分析查询字符串(您也可以因不同原因通过不同的查询字符串 :) 。

然后我们得到被点击的元素 并检查它是否拥有 x-all 属性;如果是的话,我们从 URL 中删除所有参数,否则我们分割 x-param 按逗号进行属性,并删除其中的每一项参数。

然后我们用更新的查询字符串创建一个新的 URL, 并使用 HTMX 对该 URL 提出请求 。

export function queryParamClearer({ path = window.location.pathname }) {
    return {
        clearParam(e) {
            const el = e.target.closest('[x-param],[x-all]');
            if (!el) return;

            const url = new URL(window.location.href);

            if (el.hasAttribute('x-all')) {
                // → delete every single param
                // we copy the keys first because deleting while iterating modifies the collection
                Array.from(url.searchParams.keys())
                    .forEach(key => url.searchParams.delete(key));
            } else {
                // → delete only the named params
                (el.getAttribute('x-param') || '')
                    .split(',')
                    .map(p => p.trim())
                    .filter(Boolean)
                    .forEach(key => url.searchParams.delete(key));
            }

            const qs = url.searchParams.toString();
            const newUrl = path + (qs ? `?${qs}` : '');

            showAlert(newUrl);
            htmx.ajax('GET', newUrl, {
                target: el.dataset.target || el.getAttribute('hx-target') || 'body',
                swap: 'innerHTML',
                pushUrl: true
            });
        }
    };
}

//In your entry point / anywhere you want to register the module
import { queryParamClearer } from './param-clearer.js'; // webpackInclude: true

window.queryParamClearer = queryParamClearer;

缩略 showAlert 函数使用 SweetAlert2 函数

你也会注意到我打给 showAlert 函数。 这只是一个简单的包装纸 围绕SweetAlert2 装载指标 我在我的项目中使用。 当然,你可以用任何你想做的事来代替它。"

这是略微调适的 我们最后一次看到它.. 这样我就能抽出 showAlert 功能,并提供给外部模块。 让我用它来 param-clearer 模块和 hx-indicator 模块。

export function registerSweetAlertHxIndicator() {
    document.body.addEventListener('htmx:configRequest', function (evt) {
        const trigger = evt.detail.elt;

        const indicatorAttrSource = getIndicatorSource(trigger);
        if (!indicatorAttrSource) return;

        // ✅ If this is a pageSize-triggered request, use our custom path
        let path;
        if (evt.detail.headers?.['HX-Trigger-Name'] === 'pageSize') {
            path = getPathWithPageSize(evt.detail);
            console.debug('[SweetAlert] Using custom path with updated pageSize:', path);
        } else {
            path = getRequestPath(evt.detail);
        }

        if (!path) return;
        evt.detail.indicator = null;
        showAlert(path);
    });
}

export function showAlert(path)
{
    const currentPath = sessionStorage.getItem(SWEETALERT_PATH_KEY);

    // Show SweetAlert only if the current request path differs from the previous one
    if (currentPath !== path) {
        closeSweetAlertLoader();
        sessionStorage.setItem(SWEETALERT_PATH_KEY, path);


        Swal.fire({
            title: 'Loading...',
            allowOutsideClick: false,
            allowEscapeKey: false,
            showConfirmButton: false,
            theme: 'dark',
            didOpen: () => {
                // Cancel immediately if restored from browser history
                if (sessionStorage.getItem(SWEETALERT_HISTORY_RESTORED_KEY) === 'true') {
                    sessionStorage.removeItem(SWEETALERT_HISTORY_RESTORED_KEY);
                    Swal.close();
                    return;
                }

                Swal.showLoading();
                document.dispatchEvent(new CustomEvent('sweetalert:opened'));

                // Set timeout to auto-close if something hangs
                clearTimeout(swalTimeoutHandle);
                swalTimeoutHandle = setTimeout(() => {
                    if (Swal.isVisible()) {
                        console.warn('SweetAlert loading modal closed after timeout.');
                        closeSweetAlertLoader();
                    }
                }, SWEETALERT_TIMEOUT_MS);
            },
            didClose: () => {
                document.dispatchEvent(new CustomEvent('sweetalert:closed'));
                sessionStorage.removeItem(SWEETALERT_PATH_KEY);
                clearTimeout(swalTimeoutHandle);
                swalTimeoutHandle = null;
            }
        });
    }
}

//Register it
import { registerSweetAlertHxIndicator, showAlert } from './hx-sweetalert-indicator.js';
registerSweetAlertHxIndicator();
window.showAlert = showAlert;

用于提醒 path 是知道何时隐藏警报的关键

HTMX

最后,我们使用 htmx.ajax 提出该请求。 这是对我们用更新查询字符串创建的新 URL 的简单 Get 请求 。

   htmx.ajax('GET', newUrl, {
                target: el.dataset.target || el.getAttribute('hx-target') || 'body',
                swap: 'innerHTML',
                pushUrl: true
            });

在结论结论中

这是使用标签助手和Alpine.js来清除 URL 参数的简单方法 。 它允许你清除所有参数, 或只是特定的参数, 使用最小代码。

logo

©2024 Scott Galloway