2012-07-02 5 views
6

Esiste una libreria Clojurescript che rende il DOM simile a una struttura dati Clojure? Ho trovato un paio di librerie come Enfocus che fanno un certo tipo di manipolazione del DOM, ma quello che voglio è essere in grado di trattare il DOM in questo modo:Interfaccia DOM Clojurescript

(get dom id) - returns element called id in dom 
(get dom id create-fn) - return element if exists, otherwise creates it 
(update-in dom [:body this that] update-fn) - set attribute on a DOM element 
(assoc parent-element id child-element) - associate child element with parent 
(conj parent child) - append child element to parent element 

e così via

+0

ok appena trovato Domina - cosa più vicina – Hendekagon

risposta

4

strutture dati Clojure sono tutti persistenti , ma nel tuo esempio sembra che tu voglia fare effetto collaterale (cioè colpire il DOM sul posto per cambiarlo).

Questo è un approccio procedurale/imperativo, quindi potrebbe valere la pena di tornare indietro e riformulare il problema in uno stile più funzionale. La mia filosofia personale è trattare le "viste come dati" e modellarle usando le persistenti strutture dati di Clojure fino all'ultimo minuto in cui ho bisogno di renderizzare.

Hai familiarità con Hiccup? L'idea è quella di rappresentare un HTML o SVG DOM utilizzando vettori semplici e mappe:

[:div {:with "attribute"} "and" [:span "children"]] 

cui è possibile costruire componendo funzioni semplici vecchi Clojure. In Clojure è possibile eseguire il rendering in HTML (utilizzando la libreria Hiccup originale), ma esistono almeno due librerie ClojureScript che eseguono il rendering direttamente nelle strutture DOM (potenzialmente esistenti). Crate è una porta stretta di Hiccup e Singult ha alcune semantiche aggiuntive come il binding dei dati ispirato a D3.js (Singult è in realtà scritto in CoffeeScript, quindi è utilizzabile da JavaScript semplice ed è più veloce di Crate).

La libreria C2 crea una semantica di data-binding sopra Singult per mantenere il DOM in sincronia con i dati sottostanti. Considerate questo modello per una lista TODO:

(bind! "#main" 
     [:section#main {:style {:display (when (zero? (core/todo-count)) "none")}} 
     [:input#toggle-all {:type "checkbox" 
          :properties {:checked (every? :completed? @core/!todos)}}] 
     [:label {:for "toggle-all"} "Mark all as complete"] 
     [:ul#todo-list (unify (case @core/!filter 
           :active (remove :completed? @core/!todos) 
           :completed (filter :completed? @core/!todos) 
           ;;default to showing all events 
           @core/!todos) 
           todo*)]]) 

(tratto da C2 TodoMVC implementation). Cose come se la casella "Seleziona tutto" sia stata verificata è derivata direttamente dai dati sottostanti (memorizzati in un atomo). Ogni volta che i dati cambiano, il modello verrà rieseguito e il dom automaticamente aggiornato.

L'idea di base è di creare mappature nella direzione di avanzamento dai dati dell'applicazione alle strutture di dati Hiccup e quindi lasciare che la libreria si occupi della sincronizzazione del DOM (aggiunta/rimozione di caratteri figlio, & c.). Se non ti devi preoccupare dello stato del DOM (è già stato aggiunto? Devo cambiare classe?) Poi una grande quantità di complessità accidentale cade.

+0

Grazie. In realtà stavo pensando in termini di rimozione dei precedenti elementi DOM e del loro scambio con quelli appena creati trattando i frammenti DOM come strutture persistenti in stile Clojure (ma implementate come frammenti DOM "immutabili"). Tuttavia, ora che ci penso, sarebbe probabilmente lento e dispendioso. Proverò la tua libreria ... può fare SVG? – Hendekagon

+0

ciao, ho provato l'esempio del grafico a barre su http://keminglabs.com/c2/, e ottengo "Errore non rilevato: TODO: restituisce la mappa degli stili degli elementi". Inoltre ci è voluto un po 'di tempo per capire quali cose: richiedere,: usare e: use-macros, dato che la maggior parte degli esempi sono frammenti di codice isolati. Sembra interessante però. Come gestisci la mappatura dei dati agli elementi dom sull'identità di quei nodi? In che modo unify sa quali dati corrispondono a quali nodi del dom e se aggiungere o meno nuovi? – Hendekagon

+0

Sì, è in grado di gestire SVG bene. Singult assegnerà automaticamente un nome agli elementi SVG comuni (, , & c.) anche per te (quindi non devi dire, ad esempio, '[: svg: rect {: x 1}]'. –