Nell'ultimo articolo, abbiamo trattato le nozioni di base delle Viste Backbone e come abilitare jQuery a manipolare senza problemi lo stesso DOM manipolato da Backbone.
In questo articolo, esploreremo come possiamo fare in modo che Backbone funzioni bene con d3.js. I concetti in questo articolo dovrebbero applicarsi a situazioni in cui si intende utilizzare Backbone con la maggior parte delle altre librerie che manipolano anche il DOM.
d3.js, scritto da Mike Bostock, è un'altra libreria ampiamente utilizzata che manipola il Document Object Model, principalmente per visualizzare i dati. In effetti, puoi diventare davvero creativo con il modo in cui i dati possono essere visualizzati.
Al livello più basso, d3.js interagisce con gli elementi HTML e / o SVG e ne modifica gli attributi associando i dati al modello di oggetto documento.
Ecco un rapido esempio di come d3 opera:
var numericalData = [1,2,3,4,5,6]; d3.select ("body"). selectAll ("p") .data (numericalData) .enter () .append ("p") .text (function (d) return "I'm number" + d + " ! ";);
Il codice precedente fa quanto segue:
corpo
elementop
elementi attualmente nel DOMdata numerica
a un selezionato p
elementop
elemento che deve ancora esistere (ad esempio, alcuni elementi in data numerica
che deve ancora essere aggiunto), crea a p
elemento e lo aggiunge il DOMp
elemento per contenere del testo (incluso il numero pertinente in data numerica
)Sfruttando ciò che abbiamo imparato nel precedente articolo, ecco una implementazione di una manipolazione DOM condivisa.
var CoolView = Backbone.View.extend (rendering: function () var html = "Io non sono un numero!
"; questo. $ el.html (html); return this;, renderVisualization: function (arrayOfData) d3.select (" body ") .selectAll (" p ") .data (arrayOfData) .enter () .append ("p") .text (function (d) return "I'm number" + d + "!";);); var coolView = new CoolView (); coolView.render (); var myData = [10, 9, 4, 2, 1]; coolView.renderWithD3 (myData);
Supponendo che il nostro obiettivo sia preservare l'esistente p
elemento e aggiungere l'altro p
elementi al DOM, quando eseguiamo il codice precedente, ci imbattiamo in un grosso problema.
Il .render ()
inserti un p
elemento con il testo "Io non sono un numero" nel DOM. Ma .renderVisualization ()
seleziona tutto esistente p
elementi nel DOM e inserisce il contenuto in questi elementi. Questo sovrascrive il testo nell'originale p
elemento, nonostante il nostro aggiungendo al DOM usando d3.append ()
.
In questo semplice esempio esistono almeno due soluzioni semplici.
Per esempi più complicati, potremmo aver bisogno di strategie alternative. Una possibile soluzione è quella di isolare una porzione del DOM che sarà gestita da una delle librerie. Per esempio:
var CoolView = Backbone.View.extend (... renderVisualization: function (arrayOfData) d3.select ("# visualizzazione") .selectAll ("p") .data (arrayOfData) .enter () .append ("p") .text (function (d) return "I'm number" + d + "!";);); var coolView = new CoolView (); var myData = [10, 9, 4, 2, 1]; coolView.renderVisualization (myData);
Nel caso precedente, Backbone continua a gestire la vista da creare. Tuttavia, diciamo che c'è un elemento da qualche parte nel DOM (all'interno o al di fuori del DOM gestito dalla vista Backbone) il cui id è "visualizzazione". Possiamo capitalizzare questo fatto esaminando tutte le nostre manipolazioni DOM relative a d3 a questo elemento. Di conseguenza, tutti i metodi con d3 concatenati, inclusi .selectAll ( "p")
e .append ( "p")
, sono eseguiti nel contesto di #visualization
.
Infine, un altro approccio alla gestione della funzionalità di visualizzazione di terze parti è l'utilizzo di visualizzazioni secondarie. Ecco come potrebbe essere.
var CoolView = Backbone.View.extend (rendering: function () var subViewA = new SubViewA (); var subViewB = new SubViewB (); // imposta il contenuto html per coolview this. $ el.html (subViewA.render () .el); // aggiungi altri contenuti html per rinfrescarlo. $ el.append (subViewB.render (). el); return this;); // Altrove, forse nel tuo router ... var coolView = new CoolView (); $ ( 'App') html (coolView.render () el.).;
In questo scenario, subViewA
potrebbe contenere contenuto non di visualizzazione, e subViewB
potrebbe contenere contenuto di visualizzazione.
Ci sono momenti in cui è necessario assicurarsi che la manipolazione del DOM d3 avvenga nello stesso contesto della vista Backbone stessa. Ad esempio, è sufficiente isolare una parte del DOM con #visualization
non fornisce alcuna garanzia che l'elemento esista all'interno o all'esterno della parte del DOM rappresentata dalla vista Backbone.
Un'alternativa è garantire che la selezione iniziale di d3 faccia riferimento allo stesso elemento di quello a cui punta questo. $ el
. Tuttavia, se tendi a non impostare EL
o uno qualsiasi dei suoi attributi direttamente, sarebbe difficile orientare sufficientemente la vista corrente usando CSS.
Fortunatamente, nella libreria d3.js esiste un metodo che abilita la selezione diretta del nodo. Lasciami presentarti d3.select (nodo)
. Secondo la documentazione, questo metodo:
Seleziona il nodo specificato. Ciò è utile se si dispone già di un riferimento a un nodo, ad esempio d3.select (this) all'interno di un listener di eventi o globale come document.body. Questa funzione non attraversa il DOM.
Questo metodo ci consente di scrivere il seguente codice e assicurare che le manipolazioni d3 si verifichino nel contesto della vista Backbone.
var CoolView = Backbone.View.extend (// nota che "el" non è impostato direttamente render: function () var html = "Io non sono un numero!
"; questo. $ el.html (html); restituisce this;, renderVisualization: function (arrayOfData) d3.select (this); // non funziona," this "fa riferimento a un oggetto Backbone d3.select (questo .el) // passa in un nodo di riferimento .selectAll ("p") .data (arrayOfData) .enter () .append ("p") .text (function (d) return "I'm number" + d + "!";););
In sintesi, ci sono una serie di considerazioni quando si rende il Backbone compatibile con altri manipolatori DOM.
Ci sono anche un certo numero di alternative da considerare, a seconda del risultato che si cerca: