Beim nächsten Schreiben einer Webanwendung für ASP.NET MVC mit Bootstrap dachte ich, dass die unvermeidliche Erstellung von HTML-Tags subtrahiert werden könnte. Hier geht es nicht um eine Reihe von Benutzersteuerelementen zum Erweitern des HTML-Bereichs. * Space, sondern darum, was etwas weiter entfernt liegt. Für Eile schlage ich vor, dass Sie
hier schauen
(GitHub) , und für den Rest, willkommen bei Katze.
Herausforderung
Es gibt ein HTML-Tag, das den Namen, die Klassen, Stile, Attribute usw. enthält. In .NET wird für die "manuelle" Erstellung dieser Schönheit davon ausgegangen, dass die
TagBuilder- Klasse verwendet und schrittweise mit den erforderlichen Meta- und Nur-Daten gefüllt wird.
Aber!
Der regelmäßige Gebrauch dieser Klasse erschien mir zu trostlos. Konstante * .AddCssClass, * .Attributes.Add, * .MergeAttribute und * .ToString (TagRenderMode.SelfClosing) - beginnen irgendwann, sich über ihre schrittweise Anleitung zu ärgern.
Hier ist ein Beispiel dafür, wie ein Standardschaltflächenelement aussieht:
<button type="button" class="btn btn-success">Success</button>
Wir fügen hier hinzu, dass manchmal HTML-Tags verschachtelt werden müssen, was bedeutet, dass Sie einen oder mehrere * .InnerHtml mit einem Parameter benötigen, von denen jeder auf die gleiche Weise erstellt werden sollte - Schritt für Schritt in langen Dimensionen - es wird klar, dass Sie etwas wollen etwas weniger Routine.
So wurde die
TagDecorator- Klasse geboren.
Das angegebene Problem, das ich lösen möchte, lautet wie folgt:
Um die Erstellung von HTML-Tags zu vereinfachen, gehen Sie nicht Schritt für Schritt vor und organisieren Sie die natürliche Verschachtelung der HTML-Hierarchie.Lösung
Link:
TagDecoratorIn der Anfangsphase bestand die Lösung aus zwei Klassen, anschließend wurde ihnen eine weitere hinzugefügt:
TagDecorator ist die Hauptarbeiterklasse, die dafür verantwortlich ist, einfachen Text in eine Klasse umzuwandeln, die ein Tag (TagWrapper) darstellt, an das zusätzliche Erweiterungen angehängt werden können. Im vorhandenen Beispiel gibt es sowohl allgemeine Funktionen AddAttribute, AddCss als auch private Funktionen AddType, AddName, AddId, mit denen bestimmte Attribute erstellt werden.
TagWrapper ist eine Klasse, die ein Tag darstellt. Es wurde erstellt, um sich nach Möglichkeit vollständig von TagBuilder zu entfernen, und die neuen Erweiterungen in IntelliSense wurden nicht mit den Eigenschaften der TagBuilder-Klasse verwechselt.
Tags - Die Klasse, die zum Trennen von Start- / End-Tags benötigt wird, um die in RazorView verwendeten HTML-Framing-Blöcke zu implementieren
@using(Html.SuchExtension) {
Beispiele
Im angegebenen Schaltflächenbeispiel sind die Vorteile der Verwendung von TagDecorator nicht so offensichtlich:
var htmlString = "button".ToTag() .AddType("button") .AddCss(new[] {"btn", "btn-success"}) .SetText("Success") .ToString();
Aber jetzt mit dem Beispiel der
Bootstrap-Karte - alles wird für das Auge schon viel angenehmer:
TagBuilder verwenden
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);
Version mit 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();
Ergebnisse
Nachteile
Ich glaube, dass die kaskadierende Implementierung den Code manchmal nach rechts verschiebt und oft über die Vision des Entwicklers hinausgeht. Je komplexer die Hierarchie ist, desto stärker
Vorteile
+ Codezeile - reduziert. In den einfachsten Elementen ergibt sich in einem komplexen HTML-Baum ein Gewinn von ungefähr 1-2 Zeilen - analog ungefähr 1/3, wenn Sie TagBuilder verwenden.
+ Sichtbarkeit - Sie können deutlich sehen, wo und welche Art von Verschachtelung. Alles ist hierarchisch intuitiv und leichter zu verstehen.
+ Erweiterbarkeit - ein bestimmter Fall / Attribut ist erforderlich - fügen Sie einfach die Erweiterung hinzu. Eine Zustandsprüfung ist erforderlich - Erweiterung hinzufügen.
Mögliche Verbesserungen
Zuerst habe ich darüber nachgedacht, vollständig spezialisierte Tags basierend auf diesen Klassen zu erstellen, die nur bestimmte Erweiterungen im Tooltip zulassen. Entfernen Sie beispielsweise den Tooltip für die AddReference-Erweiterung im Button-Tag, geben Sie diese Pläne jedoch aus Gründen der Universalität auf. Aber im Allgemeinen - diese Lösung hilft mir jetzt sehr bei meinen Projekten.
Es sollte auch ein NuGet-Paket erstellt werden, aber aus Zeitmangel wird alles verschoben.