作者:周茜闹心_325 | 来源:互联网 | 2023-09-15 10:57
目录
介绍
背景
开发代码
辅助功能问题
兴趣点
介绍 按照说明将 jQuery 自动完成小部件实现到 ASP.NET 页面并不困难。但是,如果使用 partial 将多个自动完成小部件添加到页面中,则需要执行一些额外的工作。当必须使用 Web 可访问性时也是如此。
背景 它是一个 ASP.NET Core MVC Razor 视图页面。
最初, Selectize 将四个文本输入框转换为选择列表框。其中两个是经理用的,因为项目的数量不多,所以选择框是可以的。另外两个是针对成百上千的员工,而选择框并不是一个好的参与者。
开发代码 以下是作为 MVC 部分页面的自动完成小部件的第一个版本。
_AutoComplete.cshtml :
@using System.Web @{Layout = null; }@* The reason to change the jquery built-in autocomplete styles is that the page is Bootstrapped *@
在主机页面中,可以像这样调用 partial :
asp-for="ManagerEmail" placeholder="Start typing an email..."> @await Html.PartialAsync("~/Views/Partials/_AutoCompletion.cshtml", new ViewDataDictionary(ViewData) {{ "TargetId", "ManagerEmail" },{ "TargetHiddenValueElementId", "ManagerContactId" },{ "Source", JsonConvert.SerializeObject(Model.Contacts.Select(x => new { value = x.Id, label = x.Name })) },// Or replace "Source" with // { "AjaxUrl", Url.Action("GetByEmail", "Contact") }, // for ajax call when data is bigger.{ "ValueType", "String" } })
如果源数据是通过 ViewData 被传递给 partial 的,则 partial 将使用浏览器本地数据。如果没有,但是使用 AjaxUrl ,将触发 Ajax 调用以从控制器操作或 Web 服务中提取数据。 因此它适用于本地和远程数据。
但是如果 z-index 值不够大,菜单选项就会出现问题。在我的例子中,其中一个小部件在 bootstrap modal 对话框中使用。这是截图:
要解决此问题,我们应该为其 z-index 设置一个大数字。它应该大于对话框的 z-index 。稍后会对此进行另一次讨论。这是我们应该通过 jQuery UI 复制此窗口小部件所需的样式的一个原因。
另一个原因是,由于我们使用其他库,如 Bootstrap 和 jqGrid ,因此可能会覆盖所需的 CSS ,因此窗口小部件可能没有预期的外观。
如果只有一个自动完成小部件,则此部分工作。如上所述,总共有 4 个。令我惊讶的是,一旦我应用了所有小部件,当我输入一个小部件时,菜单出现在另一个小部件下方。经过调查,我发现了一个问题。下面是第二个版本,它看起来像一个封装的部分,因此多个实例不会引起冲突。
_AutoComplete.cshtml 版本。 2 :
@using System.Web @{Layout = null; }@{@* The reason to change the jquery built-in autocomplete styles is that the page is Bootstrapped *@var styles = @" "; }
此版本适用于同一页面上的任意数量的小部件。此外,有两点值得一提:
窗口小部件所需的样式只添加一次而不重复。 z-index 值可以用非常大的数字进行硬编码 999999 。但是,我喜欢使用所列的计算方法。 辅助功能问题
我使用 WAVE 插件来评估 Web 可访问性。令人惊讶的是,有多种表格标签错误,乍一看似乎令人难以置信。
为什么?这是因为使用相同模型呈现的分部(不是自动完成窗口小部件,但是接触部分)的多个实例。例如,要添加和更新经理联系人,两个呈现的部分使用相同的管理器联系模型。员工联系人部分也是如此。
为了解决这个问题,我们需要在页面上绑定 / 呈现的相同模型之间区分表单标签的属性和字段 id 值。
直观地,人们可能倾向于编写 Javascript 代码来更改属性的标签和相应的表单控件 ID 。它应该可以工作,但我没有尝试这种方法,因为我们可以利用 ASP.NET Core MVC 强大的标记帮助程序来编写更清晰,更高效的代码。
我就是这样做的。
标记助手:标签标记助手和输入标记助手。
[HtmlTargetElement("label", Attributes = "asp-for")] public class ResolveMultipleAriaLabelsLabelTagHelper : LabelTagHelper {public ResolveMultipleAriaLabelsLabelTagHelper(IHtmlGenerator generator) : base(generator){}public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output){var viewData = ViewContext.ViewData;if (viewData["IdPrefixForMultipleAriaLabels"] != null){var forAttribute = output.Attributes.FirstOrDefault(attribute => attribute.Name.ToLower() == "for");if (forAttribute != null){CreateOrMergeAttribute(string.Format("{0}_{1}", viewData["IdPrefixForMultipleAriaLabels"], forAttribute.Value), output);}}var hiddenAriaAttr = output.Attributes.FirstOrDefault(attribute => attribute.Name.ToLower() == "aria-hidden");if (hiddenAriaAttr != null && hiddenAriaAttr.Value.ToString() == "true"){output.TagName = "div";#region keep the look and feel by design as much as possibleoutput.Attributes.Add("class", "label-p");output.Attributes.Add("style", "cursor:pointer");#endregion}return base.ProcessAsync(context, output);}private void CreateOrMergeAttribute(string forName, TagHelperOutput output){if (string.IsNullOrEmpty(forName)) return;var attribute = new TagHelperAttribute("for", forName);output.Attributes.SetAttribute(attribute);} }
[HtmlTargetElement("input", Attributes = "asp-for")] public class ResolveMultipleAriaLabelsInputTagHelper : InputTagHelper {public ResolveMultipleAriaLabelsInputTagHelper(IHtmlGenerator generator) : base(generator){}public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output){var viewData = ViewContext.ViewData;if (viewData["IdPrefixForMultipleAriaLabels"] != null){var nameAttribute = output.Attributes.FirstOrDefault(attribute => attribute.Name.ToLower() == "name");CreateOrMergeAttribute(string.Format("{0}_{1}", viewData["IdPrefixForMultipleAriaLabels"], nameAttribute.Value), output);}return base.ProcessAsync(context, output);}private void CreateOrMergeAttribute(string id, TagHelperOutput output){if (string.IsNullOrEmpty(id)) return;var attribute = new TagHelperAttribute("Id", id);output.Attributes.SetAttribute(attribute);} }
背后的想法是在必要时更改标签的属性和输入 ID ,以便它们可以一对一匹配。
如果我们希望它以可分辨的 label-for 和 input-id 呈现,请按以下方式调用分部:
@await Html.PartialAsync("~/Views/Partials/_AddContact.cshtml", new Contact { CanAssociateAccount = false }, new ViewDataDictionary(ViewData) { { "IdPrefixForMultipleAriaLabels", "Manager" } })
IdPrefixForMultipleAriaLabels 变量由 ViewContext 中携带的 ViewData 传递到标记助手中。然后可以将 Contact 字段呈现为以下内容:
First Name
然后,标签的 for 属性仅与前缀为 “ Manager_ ” 的输入 id 匹配。应用此功能后, WAVE 将永远不会抱怨 Contact 部分中单个输入的多个标签。虽然辅助工具可能没有多个标签的问题,但项目所有者会对修复感到满意。
兴趣点 使用 Javascript 函数在一个页面上隔离相同的部分 jQuery 自动完成小部件,用于使用本地或远程数据,具体取决于数据大小 使用 ASP.NET Core MVC 标记帮助程序来解决可访问性问题 用户数据从视图页面传递到标记助手以执行有条件的工作
原文地址:https://www.codeproject.com/Articles/1368309/What-Did-I-Do-with-this-Page