Files
AcdiuTools/TagHelpers/BsIconTagHelper.cs

167 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.VisualBasic;
using System.Threading.Tasks;
using AcdiuTools.Constants;
namespace AcdiuTools.TagHelpers
{
/// <summary>
/// <see langword="Bootstrap Icons"/> SVG Sprite 封装标签。
/// <para>支持自动缩放逻辑:若未指定宽高,则默认添加 w-1r/h-1r 类名以适配响应式根字号。</para>
/// </summary>
/// <example>
/// 用法: &lt;bsicon i="heart-fill" w="20" f="red" /&gt;
/// 或: &lt;bsicon icon="alarm" width="1rem" cn="my-style" /&gt;
/// </example>
[HtmlTargetElement("bsicon")]
public class BsIconTagHelper : TagHelper
{
// 内部逻辑变量
private string _iconName = string.Empty;
private string _width = string.Empty;
private string _height = string.Empty;
private string _fill = "currentColor";
#region ()
/// <summary>
/// 图标名称 (必填)。对应 SVG 中的 ID。
/// </summary>
[HtmlAttributeName("i")]
public string I { get => _iconName; set => _iconName = value; }
/// <summary>
/// 图标名称 (别名)。
/// </summary>
[HtmlAttributeName("icon")]
public string Icon { get => _iconName; set => _iconName = value; }
/// <summary>
/// 宽度。支持数字或 CSS 单位(如 16, 1rem
/// <remarks>若为空则尝试使用高度值,若均为空则添加默认响应式类名。</remarks>
/// </summary>
[HtmlAttributeName("w")]
public string W { get => _width; set => _width = value; }
/// <summary>
/// 宽度 (别名)。
/// </summary>
[HtmlAttributeName("width")]
public string Width { get => _width; set => _width = value; }
/// <summary>
/// 高度。支持数字或 CSS 单位。
/// </summary>
[HtmlAttributeName("h")]
public string H { get => _height; set => _height = value; }
/// <summary>
/// 高度 (别名)。
/// </summary>
[HtmlAttributeName("height")]
public string Height { get => _height; set => _height = value; }
/// <summary>
/// 填充颜色。默认为 <c>currentColor</c>。
/// </summary>
[HtmlAttributeName("f")]
public string F { get => _fill; set => _fill = value; }
/// <summary>
/// 填充颜色 (别名)。
/// </summary>
[HtmlAttributeName("fill")]
public string Fill { get => _fill; set => _fill = value; }
/// <summary>
/// 自定义 CSS 类名。
/// </summary>
[HtmlAttributeName("c")]
public string C { get; set; } = string.Empty;
/// <summary>
/// 自定义 CSS 类名 (别名)。
/// </summary>
[HtmlAttributeName("cn")]
public string CN { get; set; } = string.Empty;
/// <summary>
/// 自定义 CSS 类名 (别名)。
/// </summary>
[HtmlAttributeName("class")]
public string ClassName { get; set; } = string.Empty;
/// <summary>
/// 自定义 SVG Sprite 路径。
/// <remarks>不填则使用系统默认常量路径。</remarks>
/// </summary>
[HtmlAttributeName("path")]
public string CustomPath { get; set; } = string.Empty;
#endregion
/// <summary>
/// 处理标签渲染逻辑
/// </summary>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (string.IsNullOrWhiteSpace(_iconName))
{
output.SuppressOutput();
return;
}
// 1. 设置基础标签属性
output.TagName = "svg";
output.TagMode = TagMode.StartTagAndEndTag;
output.Attributes.SetAttribute("fill", _fill);
output.Attributes.SetAttribute("viewBox", "0 0 16 16");
// 2. 处理宽高与类名逻辑
bool hasW = !string.IsNullOrWhiteSpace(_width);
bool hasH = !string.IsNullOrWhiteSpace(_height);
if (hasW || hasH)
{
// 只要设置了任意一个,就手动赋值 width/height 属性
output.Attributes.SetAttribute("width", hasW ? _width : _height);
output.Attributes.SetAttribute("height", hasH ? _height : _width);
// 设置类名(不添加默认响应式类)
output.Attributes.SetAttribute("class", ClassName);
}
else
{
// 均未设置,则应用响应式默认类名并去重
output.Attributes.SetAttribute("class", BuildResponsiveClasses(ClassName));
}
// 3. 构建内部内容
string finalPath = string.IsNullOrWhiteSpace(CustomPath)
? UIConstants.Paths.DefaultIconSprite
: CustomPath;
output.Content.SetHtmlContent($@"<use xlink:href=""{finalPath}#{_iconName}""></use>");
}
/// <summary>
/// 构建响应式类名字符串,确保默认类名存在且去重
/// </summary>
private string BuildResponsiveClasses(string userClassName)
{
var classes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
UIConstants.Classes.DefaultWidth,
UIConstants.Classes.DefaultHeight
};
if (!string.IsNullOrWhiteSpace(userClassName))
{
var userParts = userClassName.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var item in userParts) classes.Add(item);
}
return string.Join(" ", classes);
}
}
}