将 TagHelper 绑定到以 data- 开头的属性

Bind TagHelper to attribute starting with data-

我目前正在开发 ASP.Net Core 3.0 pre-release 8 MVC 应用程序。我创建了一个自定义标签助手,它看起来像下面这样,它与现有的 asp-append-version 属性基本相同,但使用 data-src 属性而不是 src:

[HtmlTargetElement(
    "img",
    Attributes = AppendVersionAttributeName + "," + SrcAttributeName,
    TagStructure = TagStructure.WithoutEndTag)]
public class ImageTagHelper : UrlResolutionTagHelper
{
    private const string AppendVersionAttributeName = "asp-append-version-lazy";
    private const string SrcAttributeName = "data-src";


    [ActivatorUtilitiesConstructor]
    public ImageTagHelper(
        IFileVersionProvider fileVersionProvider,
        HtmlEncoder htmlEncoder,
        IUrlHelperFactory urlHelperFactory)
        : base(urlHelperFactory, htmlEncoder)
    {
        FileVersionProvider = fileVersionProvider;
    }

    public override int Order => -1000; 

    [HtmlAttributeName(SrcAttributeName)]
    public string? Src { get; set; }


    [HtmlAttributeName(AppendVersionAttributeName)]
    public bool AppendVersion { get; set; }

    internal IFileVersionProvider FileVersionProvider { get; private set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (output == null)
        {
            throw new ArgumentNullException(nameof(output));
        }

        output.CopyHtmlAttribute(SrcAttributeName, context);
        ProcessUrlAttribute(SrcAttributeName, output);

        if (AppendVersion)
        {
            EnsureFileVersionProvider();

            Src = output.Attributes[SrcAttributeName].Value as string;

            output.Attributes.SetAttribute(SrcAttributeName, FileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, Src));
        }
    }

    private void EnsureFileVersionProvider()
    {
        if (FileVersionProvider == null)
        {
            FileVersionProvider = ViewContext.HttpContext.RequestServices.GetRequiredService<IFileVersionProvider>();
        }
    }
}

无论如何,重要的部分是我想要的属性是 data-src,但是当我尝试在任何视图中使用我的 Tag Helper 时,它会给我以下错误:

Invalid tag helper bound property '..'. Tag helpers cannot bind to HTML attributes with name 'data-src' because the name starts with 'data-'.

实际问题

这是什么原因,还有什么办法可以解决"around"吗?

根据the source,这是原因:

data-* attributes are explicitly not implemented by user agents and are not intended for use on the server; therefore it's invalid for TagHelpers to bind to them.

因此,我们的想法是明确阻止 data- 属性在服务端进行评估,作为它们仅出于客户端评估目的传输数据的一种方式。

无法规避此限制,因为它内置于 Razor SDK 中,该 SDK 在使用您的标签助手的地方编译 Razor 视图。

仔细想想,有这种限制是有道理的,尤其是当你完全自由地在标签助手上使用你想要的任何属性时。如果你想使用 data- 属性,因为你想在 之后公开它们 你的标签助手有 运行,那么实际上没有什么能阻止你这样做始终可以添加其他属性作为标签助手执行的一部分:包括 data- 属性。

无法在服务器端使用data-*属性,然后在客户端进行更改!

1.Custom ImageTagHelper代码:

using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Text.Encodings.Web;

namespace YourAssemblyName.TagHelpers
{
    [HtmlTargetElement(
        "img",
        Attributes = AppendVersionAttributeName + "," + SrcAttributeName,
        TagStructure = TagStructure.WithoutEndTag)]
    public class ImageTagHelper : UrlResolutionTagHelper
    {
        private const string AppendVersionAttributeName = "asp-append-version-lazy";
        private const string SrcAttributeName = "lazy-src";

        [ActivatorUtilitiesConstructor]
        public ImageTagHelper(
            IFileVersionProvider fileVersionProvider,
            HtmlEncoder htmlEncoder,
            IUrlHelperFactory urlHelperFactory)
            : base(urlHelperFactory, htmlEncoder)
        {
            FileVersionProvider = fileVersionProvider;
        }

        public override int Order => -1000;

        /// <summary>
        /// Source of the image.
        /// </summary>
        /// <remarks>
        /// Passed through to the generated HTML in all cases.
        /// </remarks>
        [HtmlAttributeName(SrcAttributeName)]
        public string Src { get; set; }

        /// <summary>
        /// Value indicating if file version should be appended to the src urls.
        /// </summary>
        /// <remarks>
        /// If <c>true</c> then a query string "v" with the encoded content of the file is added.
        /// </remarks>
        [HtmlAttributeName(AppendVersionAttributeName)]
        public bool AppendVersion { get; set; }

        internal IFileVersionProvider FileVersionProvider { get; private set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (output == null)
            {
                throw new ArgumentNullException(nameof(output));
            }

            output.CopyHtmlAttribute(SrcAttributeName, context);
            ProcessUrlAttribute(SrcAttributeName, output);

            if (AppendVersion)
            {
                EnsureFileVersionProvider();

                // Retrieve the TagHelperOutput variation of the "src" attribute in case other TagHelpers in the
                // pipeline have touched the value. If the value is already encoded this ImageTagHelper may
                // not function properly.
                Src = output.Attributes[SrcAttributeName].Value as string;

                output.Attributes.SetAttribute(SrcAttributeName, FileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, Src));
            }
        }

        private void EnsureFileVersionProvider()
        {
            if (FileVersionProvider == null)
            {
                FileVersionProvider = ViewContext.HttpContext.RequestServices.GetRequiredService<IFileVersionProvider>();
            }
        }
    }
}

然后,您需要在客户端进行一些更改:

2.in 你的 _ViewImports.cshtml:

@addTagHelper *, YourAssemblyName

只是程序集名称,不是 命名空间,如 YourAssemblyName.TagHelpers

3.HTML代码:

<img class="lazyload" lazy-src="/logos/searchsolar-console.png" asp-append-version-lazy="true" />

4.Use 延迟加载如下:

var images = document.querySelectorAll(".lazyload");
new LazyLoad(images, {
    src: "lazy-src"
});

或者,你可以只修改jquery.lazyload.js,把所有的data-src改成lazy-src,然后像以前一样调用lazyload()