Files
AcdiuTools/TagHelpers/BsIconTagHelper.cs

127 lines
6.2 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 System.Threading.Tasks;
namespace AcdiuTools.TagHelpers
{
/// <summary>
/// <see langword="Bootstrap Icons"></see> SVG Sprite 封装标签
/// 用法: <bsicon i="heart-fill" w="16" h="16" f="red" />
/// </summary>
[HtmlTargetElement("bsicon")]
public class BsIconTagHelper : TagHelper
{
// 路径指向你存放总 SVG 的位置
/// <summary>
/// 表示用于引用图标符号的 <see langword="Bootstrap Icons"></see> SVG矢量图库文件的相对路径
/// </summary>
/// <remarks>此路径应指向包含所有 <see langword="Bootstrap"></see> 图标定义的SVG文件<br/>
/// 如果图标库被移动或升级,则需要更新该值</remarks>
const string spritePath = "/lib/bootstrap-icons-1.13.1/bootstrap-icons.svg";
/// <summary>
/// 图标名称 (必填)
/// </summary>
[HtmlAttributeName("i")]
public required string IconName { get; set; }
/// <summary>
/// 宽度 (默认为空,若为空时设置了高度,则使用高度的值,否则为元素 ClassName 添加 w-1r 以使其默认宽度为 1rem)
/// </summary>
[HtmlAttributeName("w")]
public string Width { get; set; } = string.Empty;
/// <summary>
/// 高度 (默认为空,若为空时设置了宽度,则使用宽度的值,否则为元素 ClassName 添加 h-1r 以使其默认高度为 1rem)
/// </summary>
[HtmlAttributeName("h")]
public string Height { get; set; } = string.Empty;
/// <summary>
/// 填充颜色 (默认 currentColor 即当前元素颜色)
/// </summary>
[HtmlAttributeName("f")]
public string Fill { get; set; } = "currentColor";
/// <summary>
/// 自定义 class 名称,允许用户添加额外的样式类 (默认空)
/// </summary>
[HtmlAttributeName("cn")]
public string ClassName { get; set; } = string.Empty;
/// <summary>
/// 根据指定的图标名称和属性处理标签助手以渲染SVG矢量图标
/// </summary>
/// <remarks>若未指定图标名称或为空则输出被抑制且不生成SVG<br/>
/// 渲染后,该方法会将原始标签替换为&lt;svg&gt;元素并设置标准的SVG属性<br/>
/// 包括类名、宽度、高度、填充颜色和图标ID名称。该SVG引用了 <see langword="Bootstrap Icons"></see> 中的图标<br/>
/// 使用&lt;use&gt;元素引用的矢量图形</remarks>
/// <param name="context">用于标签辅助程序执行的上下文包含当前HTML标签及其属性的相关信息</param>
/// <param name="output">标签辅助器的输出用于修改渲染的HTML元素及其内容</param>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (string.IsNullOrWhiteSpace(IconName))
{
output.SuppressOutput(); // 如果没写图标名,则不渲染
return;
}
// 1. 将外层标签替换为 <svg>
output.TagName = "svg";
output.TagMode = TagMode.StartTagAndEndTag;
// 2. 设置 SVG 基础属性
// 如果设置了 w 或 h则优先使用它们否则使用 wh 的值
// 设定机制:
// 如果 w 和 h 中任意一个不为空,则使用不为空的 w 或 h 的值同时设置宽高;
// 如果 w 和 h 都不为空,则分别使用它们设置宽高;
// 如果 w 和 h 都为空,则为其添加默认的 w-1r 和 h-1r 类以设置默认宽高为 1rem
if (!string.IsNullOrWhiteSpace(Width) || !string.IsNullOrWhiteSpace(Height))
{
// 如果用户设置了宽或高,则不添加默认的 w-1r 和 h-1r 类
output.Attributes.SetAttribute("width", !string.IsNullOrWhiteSpace(Width) ? Width : Height);
output.Attributes.SetAttribute("height", !string.IsNullOrWhiteSpace(Height) ? Height : Width);
// 继续添加用户自定义的 ClassName (如果有的话)
output.Attributes.SetAttribute("class", MergeClassNames(string.IsNullOrWhiteSpace(ClassName) ? "" : $"{ClassName}"));
}
else
{
// 如果没有设置宽高,则添加默认的 w-1r 和 h-1r 类并与用户自定义的 ClassName 合并
// 如果提供了 ClassName则判断是否为空如果不为空则将其与默认的 w-1r 和 h-1r 类合并
// 合并时使用 HashSet 来去重,确保不会重复添加相同的类名
output.Attributes.SetAttribute("class", MergeClassNames(ClassName));
}
output.Attributes.SetAttribute("fill", Fill);
output.Attributes.SetAttribute("viewBox", "0 0 16 16"); // 保证矢量对齐
//output.Attributes.SetAttribute("xmlns", "http://www.w3.org/2000/svg");
// 3. 构造内部的 <use> 节点
var content = $@"<use xlink:href=""{spritePath}#{IconName}""></use>";
output.Content.SetHtmlContent(content);
}
/// <summary>
/// 合并类名的方法,确保默认的 w-1r 和 h-1r 类与用户提供的 ClassName 合并且去重
/// </summary>
/// <param name="userClassName">用户提供的类名</param>
/// <returns>合并且去重后的类名字符串</returns>
public static string MergeClassNames(string userClassName)
{
// 定义默认的类列表
var defaultClasses = new HashSet<string> { "w-1r", "h-1r" };
// 如果用户提供了 ClassName则将其拆分成单个类并添加到集合中
if (!string.IsNullOrWhiteSpace(userClassName))
{
var userClasses = userClassName.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var cls in userClasses)
{
defaultClasses.Add(cls);
}
}
// 将集合中的类名合并成一个字符串返回
return string.Join(" ", defaultClasses);
}
}
}