Backbone-weergaven en de DOM deel 2

In het laatste artikel hebben we de basis van Backbone Views besproken en hoe je jQuery in staat stelt om dezelfde DOM naadloos te manipuleren als Backbone manipuleert.

In dit artikel zullen we onderzoeken hoe we Backbone goed kunnen laten spelen met d3.js. De concepten in dit artikel moeten van toepassing zijn op situaties waarin u van plan bent Backbone te gebruiken met de meeste andere bibliotheken die ook de DOM manipuleren.

Backbone + d3.js Werken op dezelfde DOM

d3.js, geschreven door Mike Bostock, is een andere veelgebruikte bibliotheek die het Document Object Model manipuleert, voornamelijk om gegevens te visualiseren. In feite kunt u echt creatief worden met de manier waarop gegevens kunnen worden gevisualiseerd.

Op het laagste niveau werkt d3.js samen met HTML- en / of SVG-elementen en manipuleert hun kenmerken door gegevens aan het documentobjectmodel te koppelen.

Hier is een kort voorbeeld van hoe d3 werkt:

var numericalData = [1,2,3,4,5,6]; d3.select ("body"). selecteer All ("p") .data (numericalData) .enter () .append ("p") .text (functie (d) ga terug "I'm number" + d + " ! ";); 

De bovenstaande code doet het volgende:

  1. Selecteert en maakt een verwijzing naar de lichaam element
  2. In die selectie selecteert u alle p elementen die zich momenteel in de DOM bevinden
  3. Voegt elk element toe numerieke data naar een geselecteerd p element
  4. Voor elk p element dat moet nog bestaan (d.w.z. sommige elementen in numerieke data die nog moet worden toegevoegd), creëert een p element en voegt het de DOM toe
  5. Stelt het tekstknooppunt in elk nieuw in aangemaakt p element om wat tekst te bevatten (inclusief het relevante nummer in numerieke data)

Een eerste poging om Backbone en d3.js te spelen Speel goed

Gebruikmakend van wat we in het vorige artikel hebben geleerd, is hier één implementatie van een gedeelde DOM-manipulatie.

var CoolView = Backbone.View.extend (render: function () var html = "

Ik ben geen nummer!

"; this. $ el.html (html); retourneer dit;, renderVisualization: function (arrayOfData) d3.select (" body ") .select All (" p ") .data (arrayOfData) .enter () .append ("p"). tekst (functie (d) terug "Ik ben nummer" + d + "!";);); var coolView = new CoolView (); coolView.render (); var myData = [10, 9, 4, 2, 1]; coolView.renderWithD3 (myData);

Houston, we hebben een probleem!

Ervan uitgaande dat ons doel is om het bestaande te behouden p element en voeg de andere toe p elementen naar DOM, wanneer we de bovenstaande code uitvoeren, komen we al snel een groot probleem tegen.

De .render () inserts een p element met de tekst "Ik ben geen nummer" in de DOM. Maar .renderVisualization () selecteert alle bestaande p elementen in de DOM en voegt inhoud in die elementen in. Deze overschrijven de tekst in het origineel p element, ondanks ons aanhangen naar de DOM met d3.append ().

Oplossingen om d3.js en backbone goed te laten spelen

In dit eenvoudige voorbeeld bestaan ​​ten minste twee eenvoudige oplossingen.

  1. Gebruik een specifiekere CSS-selector
  2. Gebruik een andere tag helemaal

Een gedeelte van de DOM afsnijden

Voor meer gecompliceerde voorbeelden, kunnen we alternatieve strategieën nodig hebben. Een mogelijke oplossing is om een ​​deel van de DOM af te sluiten dat door een van de bibliotheken wordt gebruikt. Bijvoorbeeld:

var CoolView = Backbone.View.extend (... renderVisualization: function (arrayOfData) d3.select ("# visualization") .select All ("p") .data (arrayOfData) .enter () .append ("p") .text (functie (d) ga terug "I'm number" + d + "!";);); var coolView = new CoolView (); var myData = [10, 9, 4, 2, 1]; coolView.renderVisualization (MyData); 

In het bovenstaande geval blijft Backbone de te creëren weergave beheren. Laten we echter stellen dat er ergens een element in de DOM zit (binnenin of buiten de DOM die wordt beheerd door de Backbone-weergave), waarvan het ID 'visualisatie' is. We kunnen van dit feit profiteren door al onze D3-gerelateerde DOM-manipulaties naar dit element te scannen. Dientengevolge, alle d3 geketende methoden, inclusief .selectAll ( "p") en .voegen ( "p"), worden uitgevoerd in de context van #visualization.

Encapsulate Differentiated DOM Manipulation With Sub-Views

Ten slotte is een andere benadering voor het beheren van de weergave van externe weergaven het gebruik van subweergaven. Hier is hoe dat eruit zou kunnen zien.

var CoolView = Backbone.View.extend (render: function () var subViewA = new SubViewA (); var subViewB = new SubViewB (); // stel de html-inhoud in voor coolview this. $ el.html (subViewA.render () .el); // voeg meer html-inhoud toe aan coolview this. $ el.append (subViewB.render (). el); retourneer dit;); // Elders, misschien in uw router ... var coolView = new CoolView (); $ ( 'App') html (coolView.render () el.).; 

In dit scenario, subViewA bevat mogelijk niet-visualiserende inhoud, en subViewB kan visualisatie-inhoud bevatten.

Een andere Shared-DOM Manipulation-aanpak voor Backbone + d3.js

Er zijn tijden dat u ervoor moet zorgen dat uw D3 DOM-manipulatie plaatsvindt in dezelfde context als de Backbone-weergave zelf. Bijvoorbeeld eenvoudigweg een gedeelte van de DOM afsplitsen met #visualization biedt geen garantie dat het element bestaat binnen of buiten het deel van de DOM dat wordt vertegenwoordigd door de Backbone-weergave.

Een alternatief is om ervoor te zorgen dat uw startende d3-selectie verwijst naar hetzelfde element als waarnaar is verwezen dit. $ el. Als u echter niet wilt instellen el of een van de attributen direct, het zou moeilijk zijn om de huidige weergave voldoende te richten met behulp van CSS.

Gelukkig bestaat er in de bibliotheek d3.js een methode die directe knooppuntselectie mogelijk maakt. Laat me je voorstellen aan d3.select (knooppunt). Volgens de documentatie is deze methode:

Selecteert het opgegeven knooppunt. Dit is handig als u al een verwijzing naar een knooppunt hebt, zoals d3.selecteer (dit) binnen een gebeurtenislistener of een globale zoals document.body. Deze functie loopt niet over de DOM.

Met deze methode kunnen we de volgende code schrijven en ervoor zorgen dat d3-manipulaties plaatsvinden binnen de context van de Backbone-weergave.

var CoolView = Backbone.View.extend (// merk op dat "el" niet direct wordt ingesteld render: function () var html = "

Ik ben geen nummer!

"; this. $ el.html (html); retourneer dit;, renderVisualization: function (arrayOfData) d3.select (this); // zal niet werken," this "verwijst naar een Backbone-object d3.select (dit .el) // doorgeven in een knoopreferentie .selectAlleen ("p") .data (arrayOfData) .enter () .append ("p") .text (functie (d) ga terug "I'm number" + d + "!";););

Conclusie

Samenvattend zijn er een aantal overwegingen bij het goed spelen van Backbone met andere DOM-manipulators.

  1. Zorg ervoor dat u het juiste element selecteert om te manipuleren. Het gebruik van specifieke CSS-klassen en id's kan het leven veel eenvoudiger maken.
  2. Slim gebruik van de verschillende DOM-manipulatiemethoden in beide bibliotheken kan een lange weg te gaan. Zorg ervoor dat u de DOM-actie duidelijk maakt (toevoegen, invoegen, invoegen, verwijderen) die u echt nodig hebt.
  3. Looping-bewerkingen in de DOM kunnen lastig zijn. Zorg ervoor dat de juiste elementen worden beïnvloed.

Er zijn ook een aantal alternatieven om te overwegen, afhankelijk van de uitkomst die u zoekt:

  1. Een deel van de DOM scheiden
  2. De DOM-manipulatie van de andere bibliotheek verkennen naar de Backbone-context
  3. Subweergaven gebruiken om de impact van andere DOM-manipulators in te kapselen