ASP.NET Core 的 "asp-fallback-*" CDN 标签助手如何工作?

How do ASP.NET Core's "asp-fallback-*" CDN tag helpers work?

我了解 asp-fallback-* 标签助手的作用。我不明白的是如何。

例如:

<link rel="stylesheet"
      href="//ajax.aspnetcdn.com/ajax/bootstrap/3.3.5/css/bootstrap.min.css"
      asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
      asp-fallback-test-class="sr-only"
      asp-fallback-test-property="position"
      asp-fallback-test-value="absolute" />

这会从 CDN 加载 bootstrap,如果 CDN 关闭则加载本地副本。

但是它是如何决定这样做的呢?我假设它会检查 asp-fallback-test-classasp-fallback-test-propertyasp-fallback-test-value。但是这些属性是什么意思?

如果我想从 CDN 连接一些其他库,我需要为它们提供一些东西,但我不确定放在那里什么。

有很多这样的例子,但我找不到关于它如何工作的解释。

更新
我并不是真的想了解标签助手是如何工作的——它们是如何呈现的,等等。我试图了解如何为这些属性选择值。例如,jQuery 后备脚本通常有 asp-fallback-test="window.jQuery",这是有道理的 - 这是一个测试,看看 jQuery 是否已加载。但是我上面展示的那些是完全不同的。如何选择它们?如果我想使用其他一些 CDN 交付的库,我需要为这些属性指定值……我会使用什么?为什么选择这些人 bootstrap?

更新 2
要了解回退过程本身是如何工作的,以及这些标签是如何编写的,请参阅@KirkLarkin 的回答。要了解为什么使用这些测试值,请参阅我的回答。

更新 3
bootstrap 5 中,sr-only class 重命名为 visually-hidden

TL;DR:

  • 一个 <meta> 标签被添加到 DOM 中,它的 CSS class 为 sr-only
  • 附加JavaScript写入DOM,其中:
    1. 找到所述 <meta> 元素。
    2. 检查所述元素是否具有设置为 absolute.
    3. 的 CSS 属性 position
    4. 如果没有设置这样的 属性 值,将向 DOM 写入一个额外的 <link> 元素,href~/lib/bootstrap/dist/css/bootstrap.min.css

针对您的 <link> 元素运行的 LinkTagHelper class 在输出 HTML 中插入一个 <meta> 元素,该元素被赋予 CSS class 个 sr-only。该元素最终看起来像这样:

<meta name="x-stylesheet-fallback-test" content="" class="sr-only" />

生成元素的代码如下所示(来源):

builder
    .AppendHtml("<meta name=\"x-stylesheet-fallback-test\" content=\"\" class=\"")
    .Append(FallbackTestClass)
    .AppendHtml("\" />");

不出所料,FallbackTestClass 的值是从 <link>asp-fallback-test-class 属性中获得的。

插入此元素后,还会插入相应的 <script> 块 (source)。代码是这样开始的:

// Build the <script /> tag that checks the effective style of <meta /> tag above and renders the extra
// <link /> tag to load the fallback stylesheet if the test CSS property value is found to be false,
// indicating that the primary stylesheet failed to load.
// GetEmbeddedJavaScript returns JavaScript to which we add '"{0}","{1}",{2});'
builder
    .AppendHtml("<script>")        
    .AppendHtml(JavaScriptResources.GetEmbeddedJavaScript(FallbackJavaScriptResourceName))
    .AppendHtml("\"")
    .AppendHtml(JavaScriptEncoder.Encode(FallbackTestProperty))
    .AppendHtml("\",\"")
    .AppendHtml(JavaScriptEncoder.Encode(FallbackTestValue))
    .AppendHtml("\",");

这里有一些有趣的事情:

  • 注释的最后一行,指的是占位符{0}{1}{2}
  • FallbackJavaScriptResourceName,表示输出到 HTML.
  • 的 JavaScript 资源
  • FallbackTestPropertyFallbackTestValue,分别从属性asp-fallback-test-propertyasp-fallback-test-value中得到。

那么,让我们看一下 JavaScript 资源 (source),它归结为具有以下签名的函数:

function loadFallbackStylesheet(cssTestPropertyName, cssTestPropertyValue, fallbackHrefs, extraAttributes)

将它与我之前调用的注释的最后一行以及 asp-fallback-test-propertyasp-fallback-test-value 的值结合起来,我们可以推断它是这样调用的:

loadFallbackStylesheet('position', 'absolute', ...)

我不会深入研究 fallbackHrefsextraAttributes 参数,因为它们应该比较明显并且您自己可以轻松探索。

loadFallbackStylesheet 的实施并没有太大作用 - 我鼓励您自己探索完整的实施。这是来源的实际检查:

if (metaStyle && metaStyle[cssTestPropertyName] !== cssTestPropertyValue) {
    for (i = 0; i < fallbackHrefs.length; i++) {
        doc.write('<link href="' + fallbackHrefs[i] + '" ' + extraAttributes + '/>');
    }
}

脚本获取相关的 <meta> 元素(假定它直接位于 <script> 本身之上)并简单地检查它是否具有 属性 的 position设置为 absolute。如果没有,额外的 <link> 元素被写入每个后备 URL.

的输出

好的,结合@KirkLarkin 的回答和常识,我想我现在明白了。

sr-only 应用于隐藏的 meta 元素。如果加载 bootstrap,则该元素将获得 position:absolute 的 css 值。这样就测试过了,如果是这样,那就说明Bootstrap已经加载了。

因此,对于任何库,您都需要选择一个只有该库才能做的事情的好例子,并相应地设置隐藏的 <meta> 标签的样式,然后指定要测试的 css 样式,以及您期望的价值是多少。

对于 javscript,它甚至更容易,因为您可以只测试库本身,它通常会在 window 或 DOM 中添加一些众所周知的变量。所以对于jQuery它是window.jQuery,对于Bootstrap它可以被测试为window.jQuery && window.jQuery.fn && window.jQuery.fn.modal等等。