En el siguiente proceso de escribir una aplicación web para ASP.NET MVC usando Bootstrap, me sorprendí pensando que la inevitable creación de etiquetas HTML podría sustraerse. No se trata de un conjunto de controles de usuario para expandir el espacio Html. *, Sino de lo que se encuentra un poco más lejos. Por prisa, te sugiero que mires
aquí (GitHub) , y por lo demás, bienvenido a cat.
Desafío
Hay una etiqueta HTML que contiene el nombre, clases, estilos, atributos, etc. En .NET, para la creación "manual" de esta belleza, se supone que usa la clase
TagBuilder y la llena gradualmente con los meta y datos necesarios.
Pero!
El uso regular de esta clase me pareció demasiado triste. Constante * .AddCssClass, * .Attributes.Add, * .MergeAttribute y * .ToString (TagRenderMode.SelfClosing) - en algún momento comienzan a molestar con su paso a paso.
Aquí hay un ejemplo de cómo se ve un elemento de botón estándar:
<button type="button" class="btn btn-success">Success</button>
Agregamos aquí que a veces las etiquetas HTML requieren anidamiento, lo que significa que se requieren uno o varios * .InnerHtml con un parámetro, cada uno de los cuales a su vez debe crearse de la misma manera: largo-dimensionalmente-paso a paso - queda claro que quieres algo Algo menos rutinario.
Así
nació la clase
TagDecorator .
El problema declarado que me gustaría resolver es el siguiente:
para simplificar la creación de etiquetas HTML, alejarme paso a paso y organizar el anidamiento natural de la jerarquía HTML.Solución
Enlace:
TagDecoratorEn la etapa inicial, la solución consistía en dos clases, pero posteriormente se les agregó otra:
TagDecorator es la clase de trabajo principal, que es responsable de convertir el texto plano en una clase que representa una etiqueta (TagWrapper), a la que se pueden adjuntar extensiones adicionales. En el ejemplo existente, hay funciones generales AddAttribute, AddCss y funciones privadas AddType, AddName, AddId, que crean atributos específicos.
TagWrapper es una clase que representa una etiqueta. Fue creado para alejarse completamente de TagBuilder siempre que sea posible y las nuevas extensiones en IntelliSense no se confundieron con las propiedades de la clase TagBuilder.
Etiquetas : la clase necesitaba separar las etiquetas de inicio / fin para que sea posible implementar los bloques HTML de trama utilizados en RazorView
@using(Html.SuchExtension) {
Ejemplos
En el ejemplo del botón indicado, las ventajas de usar TagDecorator no son tan obvias:
var htmlString = "button".ToTag() .AddType("button") .AddCss(new[] {"btn", "btn-success"}) .SetText("Success") .ToString();
Pero ahora con el ejemplo de la
tarjeta Bootstrap , todo se está volviendo mucho más agradable a la vista:
Usando TagBuilder
var divMain = new TagBuilder("div"); divMain.AddCssClass("card"); divMain.Attributes.Add("style", "width: 18rem;"); var img = new TagBuilder("img"); img.AddCssClass("card-img-top"); img.Attributes.Add("src", "..."); img.Attributes.Add("alt", "Card image cap"); var divBody = new TagBuilder("div"); divBody.AddCssClass("card-body"); var h = new TagBuilder("h5"); h.AddCssClass("card-title"); h.SetInnerText("Card title"); var p = new TagBuilder("p"); p.AddCssClass("card-text"); p.SetInnerText("Some quick example text to build on the card title and make up the bulk of the card's content."); var a = new TagBuilder("a"); a.Attributes.Add("href", "#"); a.AddCssClass("btn"); a.AddCssClass("btn-primary"); a.SetInnerText("Go somewhere"); divBody.InnerHtml += h.ToString(TagRenderMode.Normal); divBody.InnerHtml += p.ToString(TagRenderMode.Normal); divBody.InnerHtml += a.ToString(TagRenderMode.Normal); divMain.InnerHtml += img.ToString(TagRenderMode.Normal); divMain.InnerHtml += divBody.ToString(TagRenderMode.Normal); return divMain.ToString(TagRenderMode.Normal);
Versión con TagDecorator
var htmlString = "div".ToTag() .AddCss("card") .AddAttribute("style", "width: 18rem;") .InnerHtml(new [] { "img".ToTag() .AddCss("card-img-top") .AddAttributes(new[] {new[] {"src", "..."}, new[] {"alt", "Card image cap"}}), "div".ToTag() .AddCss("card-body") .InnerHtml(new [] { "h5".ToTag().AddCss("card-title").SetText("Card title"), "p".ToTag().AddCss("card-text").SetText("Some quick example text to build on the card title and make up the bulk of the card's content."), "a".ToTag().AddCss(new[] {"btn", "btn-primary"}).AddAttribute("href", "#").SetText("Go somewhere") }) }).ToString();
Resultados
Contras
El principal de los cuales creo es que la implementación en cascada a veces desplaza el código a la derecha, a menudo va más allá de la visión del desarrollador, y cuanto más compleja es la jerarquía, más fuerte
Pros
+ Línea de códigos - reducida. En los elementos más simples, hay una ganancia de aproximadamente 1-2 líneas, en un árbol HTML complejo, aproximadamente 1/3 por analogía si usa TagBuilder.
+ Visibilidad: puede ver claramente dónde y qué tipo de anidamiento. Todo es jerárquicamente intuitivo y más fácil de entender.
+ Extensibilidad: se necesita algún caso / atributo específico, solo agregue la extensión. Se necesita una verificación de condición: agregue la extensión.
Posibles mejoras.
Al principio, pensé en crear etiquetas completamente especializadas basadas en estas clases que permitieran solo ciertas extensiones en la información sobre herramientas; por ejemplo, eliminar la información sobre herramientas de extensión AddReference en la etiqueta del botón, pero luego abandoné estos planes por el bien de la universalidad. Pero en general, esta solución ahora me ayuda mucho en mis proyectos.
También se suponía que debía crear un paquete NuGet, pero por falta de tiempo, todo se pospuso.