using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.VisualBasic; using System.Threading.Tasks; using AcdiuTools.Constants; namespace AcdiuTools.TagHelpers { /// /// SVG Sprite 封装标签。 /// 支持自动缩放逻辑:若未指定宽高,则默认添加 w-1r/h-1r 类名以适配响应式根字号。 /// /// /// 用法: <bsicon i="heart-fill" w="20" f="red" /> /// 或: <bsicon icon="alarm" width="1rem" cn="my-style" /> /// [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 属性定义 (支持别名) /// /// 图标名称 (必填)。对应 SVG 中的 ID。 /// [HtmlAttributeName("i")] public string I { get => _iconName; set => _iconName = value; } /// /// 图标名称 (别名)。 /// [HtmlAttributeName("icon")] public string Icon { get => _iconName; set => _iconName = value; } /// /// 宽度。支持数字或 CSS 单位(如 16, 1rem)。 /// 若为空则尝试使用高度值,若均为空则添加默认响应式类名。 /// [HtmlAttributeName("w")] public string W { get => _width; set => _width = value; } /// /// 宽度 (别名)。 /// [HtmlAttributeName("width")] public string Width { get => _width; set => _width = value; } /// /// 高度。支持数字或 CSS 单位。 /// [HtmlAttributeName("h")] public string H { get => _height; set => _height = value; } /// /// 高度 (别名)。 /// [HtmlAttributeName("height")] public string Height { get => _height; set => _height = value; } /// /// 填充颜色。默认为 currentColor。 /// [HtmlAttributeName("f")] public string F { get => _fill; set => _fill = value; } /// /// 填充颜色 (别名)。 /// [HtmlAttributeName("fill")] public string Fill { get => _fill; set => _fill = value; } /// /// 自定义 CSS 类名。 /// [HtmlAttributeName("c")] public string C { get; set; } = string.Empty; /// /// 自定义 CSS 类名 (别名)。 /// [HtmlAttributeName("cn")] public string CN { get; set; } = string.Empty; /// /// 自定义 CSS 类名 (别名)。 /// [HtmlAttributeName("class")] public string ClassName { get; set; } = string.Empty; /// /// 自定义 SVG Sprite 路径。 /// 不填则使用系统默认常量路径。 /// [HtmlAttributeName("path")] public string CustomPath { get; set; } = string.Empty; #endregion /// /// 处理标签渲染逻辑 /// 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($@""); } /// /// 构建响应式类名字符串,确保默认类名存在且去重 /// private string BuildResponsiveClasses(string userClassName) { var classes = new HashSet(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); } } }