Erstellen benutzerdefinierter Komponenten für Bootstrap 4


Die öffentliche Meinung hat Bootstrap in die Kategorie der legendären Frameworks der Vergangenheit übersetzt, aber es ist immer noch sehenswert. Bootstrap 4 ist ein hervorragender Navigator für ein sicheres Layout. Vor allem zeigt ein Beispiel für einen HTML-über-JS- Ansatz zum Erstellen von Webanwendungen die vorhandenen Funktionen von HTML zur deklarativen Beschreibung der Benutzeroberfläche.


Und wie sich JavaScript-Framework-Code entwickelt, ist auch nützlich, um eine Idee zu haben. Die Architektur von jQuery- Plugins wird weiterhin verwendet, wird jedoch ab Version 4 von Rollup in die mit Babel6 transformierten Paket- ES6- Klassen eingeschlossen . jQuery wird wahrscheinlich nicht in Kürze verfügbar sein - dazu später mehr -, aber zunächst werden am Beispiel des Erstellens eines eigenen BsMultiSelect- Plug-Ins auf demselben Stack wie Boostrap 4 die Entwicklungsfunktionen des Frameworks enthüllt.


Warum " jeder Programmierer sollte sein eigenes schreiben ... "


" Verbesserung der guten nur Beute ." Die Notwendigkeit zu verstehen, was neues Bootstrap bekam, war die Übertragung seiner Komponenten auf den neuen Stapel und wie viel einfacher es jetzt ist, Komponenten höherer Ordnung zu erstellen. Alles schien einfach zu sein: Kombinieren Sie .form-control , .badge und .dropdown-menu und Sie erhalten ganz einfach eine Mehrfachauswahl ...



Konflikt der Architektur von der Tür


Das resultierende BsMultiSelect- Plugin verwendet nicht direkt den JS- Bootstrap.js- Code, sondern die Abhängigkeit popper.js (Vanille-Popup-Framework). Dies liegt daran, dass die Dropdown-Komponente von bootstrap.js während der Initialisierung im DOM das sogenannte Umschaltelement finden muss (in dem speziellen Fall ist es eine Schaltfläche, die das Menü öffnet). Wenn sie es nicht findet, stürzt sie mit einem Fehler ab (da ich direkt aus js erstelle, habe ich "Schaltflächen"). natürlich nicht). Fazit: Komponenten, die unter "HTML über JS" geschärft wurden, können nicht (oder nachteilig) direkt aus JS erstellt werden. Fazit Nummer zwei: Sie müssen benutzerdefinierte Komponenten so programmieren, dass unter der Komponente "HTML über JS" immer eine leichtere Komponente von "reinem JS" vorhanden ist. Ich habe diese MulitSelect.js nicht nur vom Code, sondern auch von den Bootstrap-Stilen vollständig gelöscht. MulitSelect.js spielt für BsMulitSelect.js dieselbe Rolle wie popper.js für dropdown.js.


Zwei Worte zu popper.js


Tolle Bibliothek - eine Funktion. DropDown.js wiederholt sich, bietet jedoch eine vollständig eingeschränkte Schnittstelle (da in "HTML über JS" nicht die gesamte API benötigt wird). Popper hat mehr offene Fragen als wir möchten. Ich war enttäuscht, dass unter IE11 Ereignisse veröffentlicht werden, die nicht wie unter Chrome sind .


Über den Übergang von IIFE zu Klassen


Das Standard-Boilerplate für jQuery-Plugins besteht darin, die Konstruktorfunktion in IIFE zu definieren. Dies ist eine Klasse innerhalb von IIFE. Öffnen: Alte funktionale Methoden für private Methoden stehen im Konflikt mit dem ES6-Lambda, sodass sie in Bootstrap "aufgegeben" wurden. Alle Methoden sind öffentlich, während pseudo-privaten Methoden _ vorangestellt wird, d.h. Unterstrich. Ich verstehe, dass ich falsch liege, aber ich folge meinen Konventionen - "öffentliche Methoden mit Großbuchstaben". In allem anderen hat BsMultiSelect die Annahme der Vereinbarung der "Standard" DropDown.js geschaffen, d. H. Ich möchte ihn als eine Art Boilerplate mit Fleisch darstellen.


Ein weiterer Unterschied, da es ein Rollup gibt, habe ich die Dateien getroffen.
 import $ from 'jquery' import AddToJQueryPrototype from './AddToJQueryPrototype' import MultiSelect from './MultiSelect' // ... ( (window, $) => { AddToJQueryPrototype('BsMultiSelect', (element, optionsObject, onDispose) => { // ... return new MultiSelect(element, optionsObject, onDispose, facade, window, $); }, $); } )(window, $) 

Die neue Vereinbarung: ein Plugin zu veröffentlichen Constructor - die nicht ist der Designer innerhalb IIFE zu verlieren. Ja, ein IIFE sollte verbleiben - niemand hat die Aufgabe entfernt, die Fenster-, $ und Popper-Abhängigkeiten (für diejenigen, die "nicht in Module" können) auf standardmäßige Weise zu definieren.


Eslint- und Stylelint-Linter-Konfigurationen


Ich fühlte mich nicht verpflichtet, die drakonischen Regeln für das Styling von Bootstrap-Code zu befolgen. Sicherlich schreiben sie in einer Umgebung, die ihnen beim Einstellen von Räumen und bei der strengen Kontrolle der Quellcodeverwaltung hilft, aber es fällt mir schwer, jede Sekunde auf die Trauer des Linter in VS Code zu hören. Wenn Sie Ihr eigenes Plugin schreiben, können und sollten die Regeln stark gelockert werden.


Eslint, Stylelint kommt vielleicht nicht zu oft heraus, aber es besteht kein Wunsch, sich die neuen Regeln anzuschauen. In jeder Hinsicht nervt mich diese Leistung mehr.


Organisationscode und Rollup


Der verteilbare ES6-Code von Bootstrap wird durch Rollup in zwei Versionen gepackt: Standalone bootstrap.js und Bundle bootstrap.bundle.js - letzteres enthält popper.js.


Der Autor von rollup.config.js hat mir fremde Instinkte. All diese Konfigurationstransformationen durch Push und Pop, abhängig von der erforderlichen Version von Standalone oder Bundle, sehen aufwendig und einschüchternd aus. Zum Glück benötigen Sie zum Schreiben eines Plugins nur eine Art von Bundle "Standalone", und ich muss nicht beweisen, dass ich es besser machen kann.


Eine eigenständige Version von Bootstrap wird auch im Hauptfeld des Pakets angezeigt, d.h. npm-Abhängigkeiten werden in dieselbe Datei aufgelöst, die Benutzer über <script> laden. Dies ist keine eindeutige Lösung, aber mein BsMultiSelect- Plugin ist denselben Weg gegangen . In diesem Fall können babel-Helfer in das Plugin aufgenommen werden , obwohl sie auch in bootsrap.js enthalten sind. Vervielfältigung ist irgendwie nicht richtig ...


Interessant ist, dass Bootstrap unter jspm eine parallele Konfiguration hat - der native Browser-ES-Modullader und sein Hauptfeld besteht bereits aus sauberem Remote-Code, 12 Komponenten, die nicht gebündelt, sondern separat im Verzeichnis js / dist gespeichert sind. Hier enthält jede Datei Babel Helfer. Jspm befindet sich jetzt an einem Scheideweg. Wenn Sie also BsMultiselect erstellen, ignorieren Sie es.


Und doch ist es interessant, Kenner zu fragen, ob jspm alle 12-mal duplizierten Helfer-Helfer in den Browser bringt.

Ein großes Plus an Rollup wurde entdeckt - seine Pakete sind im Gegensatz zu Webpacks lesbar.


Bootsrap 4 verwendet Babel 6 und das BsMultiSelect Babel 7-Plugin


BsMultiSelect konnte mithilfe des aktualisierten Rollup-Babel-Plugins (auch in der Beta) problemlos auf die Beta von Babel 7 migriert werden. Es lohnt sich, jetzt auf Babel 7 umzusteigen, da das neue @babel/preset-env (die Konfiguration des Transpilers, "auf welchen Browsern der Code ausgeführt wird"). Allein über das Internet wurde es ziemlich schwierig zu verstehen, wie ES6-Voreinstellungen funktionieren. Sie haben eine lange Entwicklung durchlaufen und viele veraltete Konfigurationen haben sich angesammelt. Wetten Sie besser sofort auf Babel 7 + @babel/preset-env


Trotzdem mussten die Beta-Fehler von babel nicht lange warten: [... nodeList] wurde in nodeList.concat () übertragen. Ich habe es lange nicht verstanden, den Code in JQuery-Aufrufe zu übersetzen (dies ist immer noch notwendig, aber dazu später mehr), um das Problem zu lösen. Fragen Sie: "Warum dann überhaupt Babel, wenn Sie nicht mit ihm zu tun haben?", Die Antwort: "Importe und Lambda."


Praktische Aspekte


In Bootstrap 4 und dessen Plug-in (wie jedes js - Code), gibt es zwei Varianten der Laden im Browser: durch das Skript / Stil (eine „Seite“ zu schaffen), und durch eine Montage node / webpack (create „Anwendung“, so dass ich diese beiden fortsetzen im Prinzip sehr unterschiedliche Situationen und bezeichnen: "Seite" und "Anwendung").
Für die Seite und für die Anwendung wird dieselbe Bootstrap- "Verteilungsdatei" verwendet. Dies ist keine offensichtliche und nicht die einzige Lösung (zum Beispiel wird für jspm und für mocha Tests anderer Code verwendet), aber wenn Sie ein eigenes Plugin erstellen, müssen Sie dieser Konvention nur folgen und auf ihre Optimalität hoffen.


Das Gleichgewicht zwischen der Erfüllung zweier Anforderungen mit demselben Code für zwei verschiedene Downloadoptionen zu finden: "Seiten" und "Anwendungen" ist die Hauptaufgabe der Architektur für den Plug-In-Entwickler.


Schließlich kann das Bootstrap-Plugin auch direkt in Ihrer Anwendung ad hoc erstellt werden. In diesem Fall können Sie den Plug-In-Code mit allen Freuden schreiben: Polyphile und Zugriff auf SASS-Variablen des Schemas. Wenn Sie sich jedoch auf die Wiederverwendung verlassen, müssen Sie das Plugin in ein eigenes npm-Paket übertragen. Die oben genannten Vorteile fallen in die Kategorie der Probleme: Sie verlieren den Zugriff auf SASS-Variablen und müssen die Ersteller der "Seiten" berücksichtigen, die das Plugin über das Skript verbinden (wo befinden sich meine Polydateien?).


Zugriff auf SASS Bootstrap 4-Stilvariablen


Ich möchte Bootstrap-CSS-Klassen / Selektoren zum Schreiben des Plugins schreiben. In diesem Fall können Sie beim Anpassen des Bootstrap-Themas erwarten, dass sich das Plugin ohne zusätzlichen Aufwand anpasst.


Für ein selbst veröffentlichtes Plugin gibt es keinen Zugriff auf SASS-Variablen.


Bestehende CSS-Klassen / Selektoren - decken nicht alle für BsMutliSelect erforderlichen Stile ab. Sie benötigen beispielsweise die ul.form-control für die ul.form-control , wenn in bootstrap.css nur ein input.form-control Selektor mit der Höhe für die input.form-control Sie können ihn nicht anwenden für ul . Andere vorhandene Klassen / Selektoren bringen viele überflüssige Stile mit sich: Was ist, wenn Sie einem Element beispielsweise Farbe von .form-control zuweisen möchten, ohne eine Klasse .form-control ? Dies funktioniert nicht, da es keine Klasse wie .input-color in der die Variable $ input-color "getrennt" von allem veröffentlicht würde.


Außerdem ist es nicht möglich, den Entscheidungen des Bootstrap-Teams zu folgen: Sie haben kein solches Problem, wenn sie müssen - sie erstellen eine CSS-Klasse / Selektor mit der gewünschten Variablen und bearbeiten sie. Wenn Sie diskutieren möchten, müssen Sie mit Mark Otto erklären, dass es im BS-Team ein ungewöhnlich hohes Maß an Entscheidungsfindung gibt, selbst bei kosmetischen Änderungen bei CSS-Selektoren, wenn Anfragen in die Kategorie "Angebot" fallen.


Ich schlage die folgende Lösung vor.


Für eine Seite (ein Plug-In über ein script ) müssen Sie sich mit der Unzugänglichkeit von Variablen abfinden. Es ist jedoch nicht erforderlich, den Umgang mit CSS anzubieten - unzugängliche Variablen können angeboten werden, um über js-Parameter angepasst zu werden, da es nicht viele von ihnen gibt (und nicht alle von einem Schema geändert werden). Für BsMultiSelect waren die problematischen: deaktivierte Farbe, Eingabefarbe, fokussierter Kontrollschatten (usw. nur 10 Stile, die meisten ändern selten das Schema) ...


Zum einen ist dies eine Deklaration aller Stile, von denen das Plugin abhängt ...
 $("select[multiple='multiple']").bsMultiSelect({ selectedPanelDefMinHeight: 'calc(2.25rem + 2px)', // default size selectedPanelLgMinHeight: 'calc(2.875rem + 2px)', // LG size selectedPanelSmMinHeight: 'calc(1.8125rem + 2px)', // SM size selectedPanelDisabledBackgroundColor: '#e9ecef', // disabled background selectedPanelFocusBorderColor: '#80bdff', // focus border selectedPanelFocusBoxShadow: '0 0 0 0.2rem rgba(0, 123, 255, 0.25)', // foxus shadow selectedPanelFocusValidBoxShadow: '0 0 0 0.2rem rgba(40, 167, 69, 0.25)', // valid foxus shadow selectedPanelFocusInvalidBoxShadow: '0 0 0 0.2rem rgba(220, 53, 69, 0.25)', // invalid foxus shadow inputColor: '#495057', // color of keyboard entered text selectedItemContentDisabledOpacity: '.65' // btn disabled opacity used }); 

Für eine Anwendung mit SASS und dem Collector können Sie jedoch anbieten, BsMultiSelect.scss in sich selbst zu kopieren und den Pfad zu Ihrer _variables.scss darin zu korrigieren. Somit "empfängt" das Plugin die variablen Variablen.


Alles durch CSS ...
  $("select[multiple='multiple']").bsMultiSelect({ useCss: true }); 

Diese beiden Methoden werden explizit in meinen JS-Code über zwei „Adapter“ geschrieben. BsMultiSelect besteht eigentlich aus zwei Plugins in einem. Einer , der mit den Arten der Variablen js arbeitet, eine andere delegieren diese Aufgabe css.


Gleichzeitig muss ich direkt sagen, dass die Arbeit mit CSS auch dann erforderlich sein kann, wenn die Übertragung von benutzerdefinierten Stilen über JS-Parameter verwendet wurde, einfach weil die Autoren der Schemata ihre Arbeit normalerweise sehr grob ausführen. Oder seltsam. Zum Beispiel hat das Skethy- Schema aus irgendeinem Grund entschieden, dass das Menü keinen Hover-Effekt benötigt. Features müssen abgelegt werden.


Aber mit dem skizzenhaften Beispiel hoffe ich, dass Sie sehen können, wie sich das Plug-In relativ leicht an die schwere Schaltung anpasst (es war notwendig, die Werte von nur drei Stilen durch js-Parameter zu überladen).


Anpassung an das Schema durch js
 $("select[multiple='multiple']").bsMultiSelect({ selectedPanelFocusBoxShadow:"0px 0px 0px 0.2rem rgba(51,51,51,0.25)", selectedPanelFocusBorderColor:"#333", selectedPanelDisabledBackgroundColor: "#f7f7f9" }); 


Dies ist das Maximum, das mit den "Standard" .form-control Klassen .bage , .form-control , .close usw. erreicht werden kann. Fast alles passte sich dem Schema an, aber nicht alles.


Es ist natürlich schade, dass Sie nicht von diesen drei Parametern abweichen können. Nicht auf alle Variablen im Schema-Stil kann über CSS-Selektoren / Klassen zugegriffen werden (ich lüge, Sie können es verlassen, wenn Sie BsMultiSelect.scss für sich selbst kopieren und die Schaltungsvariablen dazu bringen können, aber dies ist nicht vollständig zufriedenstellend , wie alle Entscheidungen, die mit den Worten "kopiere zu dir selbst" beginnen).


Klicken Sie hier: https://dashboardcode.imtqy.com/BsMultiSelect/indexsketchy.html


Polyfills


Im Szenario „Ich schreibe ein Ad-hoc-Plugin in die Anwendung“ verwenden Sie @babel/polyfill ohne Probleme und patchen das DOM polyfill.io, da es in Ihrer Anwendung bereits vorhanden ist.


Wenn ein Plugin in ein externes npm-Modul verschoben wird, verschwindet die ganze Freude, da Bootstrap-Benutzer nicht entschieden haben, die langen Listen der erforderlichen Polyfills in der Dokumentation zu berücksichtigen.


Lösung: Alles, was babel nicht transponiert, sondern Polyphilen überlässt, verhindert dies, knirscht mit den Zähnen, um es in jQuery-Aufrufe umzuwandeln (z. B. Node.closest in $ .closest). Dieser Ansatz wird in Bootstrap 4 selbst übernommen und ist offensichtlich ein Kampf gegen Schwellungen. Überraschung jQuery ist eine Polyfüllung.


Ich bin damit einverstanden, dass das Programmieren mit Babel mit Blick auf CanIUse.com und MDN.com keinen Spaß macht. Und der Code ist (für mich) umständlich.


Hier ist es notwendig, die Situation noch einmal von oben hervorzuheben. Bootstrap verwendet zwei jQuery- und popper.js-Bibliotheken. Popper.js ist ein Doppel-Vanille-Framework, es hat keine Babel-, JQuery- oder externen Polyfills für sich. JQuery wird von Grunzen bereits mit Babel verpackt, aber irgendwie magisch ohne seine Polyfills und Helfer. Ein Bootstrap-Plugin eines Drittanbieters (wie BsMultiSelct) verwendet Babel 7. Ihr Produkt verwendet möglicherweise noch etwas anderes. Es gibt keine einzelne polyphile Plattform, es wird eine mehrfache Codeduplizierung erwartet, es werden vier Implementierungen derselben am nächsten in den Browser geladen. Daran kann aber nichts geändert werden.


Wenn Sie beim Erstellen Ihres eigenen Plugins dennoch Polydateien verwendet haben, müssen Sie sich daran erinnern, dass die Anwendung Inline-Skripte enthält (d. H. <script>$( function() {/*..*/}) </script> ) Sie müssen Polyfiles nur synchron herunterladen (andernfalls kann der Inline-Code früher als beim Laden des Plugins ausgeführt werden). Das heißt, Zum Beispiel Webpack-Polyfill-Injektor (der reichste mir bekannte Polyphil-Injektor) Ich muss ihn so steuern, dass er nicht entscheidet, Polyphile asynchron zu laden (Standardverhalten).


Keine jQuery


jQuery fühlt sich etwas giftig an, konkurriert mit Babel / ES6 und verdeckt es, aber es ist nicht für immer. Es gibt Zweig v4-whithout-jquery , es ist bereits in der Pool-Anfrage, es ist geplant, bootstrap-nojquery c Version 4.3 zu veröffentlichen . Bisher wurde der Namespace von Ereignissen als das größte Problem beim Ablehnen von jquery bezeichnet, obwohl es offensichtlich ist, dass Sie ohne sie schreiben können (BsMultiSelect verzichtete darauf). Anscheinend entschieden.


Auch bekannt , dass Version 4.3 werden die ursprünglichen Komponenten können in separaten Browser (nur für die „Anwendung“ -Szenario) versendet werden. Werden die Originalkomponenten dann "wie BsMultiSelect "? Nein. Wenn das BS-Team einige SASS-Variablen benötigt, erstellt es CSS-Klassen / Selektoren für sich selbst und bearbeitet sie von JS ("funktionales CSS"). Benutzer von benutzerdefinierten Funktionen sind nicht verfügbar.


Der mögliche Übergang von sass zu post-css https://github.com/twbs/bootstrap/projects/11 in der 5. Version ändert grundsätzlich nichts. Oder ändert alles: "JS over HTML".


Bootstrap 5 muss Empfehlungen zur Integration in Babel-Polydateien und zum Patchen des DOM enthalten. Hier ist die Prognose mehr oder weniger klar: Seitenerstellern und Anwendungserstellern werden völlig unterschiedliche Baugruppen angeboten.


Zusammenfassung


Während Sie Bootstrap 4-Komponenten mit der Ad-hoc- Methode auf Babel schreiben, ohne über die Wiederverwendung nachzudenken, dh über Polyphile, und wo Sie die Stilvariablen erhalten, wissen Sie nichts über Trauer.


Wenn Sie das Plugin jedoch zu einem separaten npm-Paket machen - und mit dem Wunsch, eine Entscheidung im Geiste von Bootstrap 4 selbst zu treffen, wird das Vergnügen geringer, denken Sie öfter und länger. Sie müssen wahrscheinlich sofort entscheiden, wer Ihre Benutzer sind, und verschiedene Builds anbieten, einen für diejenigen, die die Anwendung in Bundles erstellen, den anderen zum Schreiben von Seiten, d. H. Laden des Plugin-Skripts.

Source: https://habr.com/ru/post/de416235/


All Articles