decument.querySelector () su elementi non in DOM?

Sto lavorando su un sito web, con jQuery ma sto cercando di non usarlo più. In jQuery puoi aggiungere un ascoltatore pari su un elemento che non era presente sul sito web o che non era ancora stato creato e nessun problema. Ho degli elementi che sono solo sul DOM quando hai effettuato l’accesso e ho solo un file JS per l’intero sito web.

Il problema è, ad esempio, quando sei loggato non puoi vedere il pulsante “accedi”, non è nemmeno nel DOM, ma ha ancora il listener di eventi nel codice, nessun errore sulla console, lo script viene eseguito bene.

$("#logInButton").on("click", somefunction); 

Ma, usando document.querySelector("#logInButton").onclick = somefunction ed essendo già loggato, genera un errore perché document.querySelector("#logInButton") è nullo.

Posso fare come:

 let logInButton = document.querySelector("#logInButton"); logInButton ? logInButton.onclick = somefunction : ""; 

E funziona bene, ma so che non è una buona pratica. Qualche soluzione o miglioramento, non usando jQuery?

JSFiddle se cosa succede. (Vedi console)

E funziona bene, ma so che non è una buona pratica.

Se l’ #logInButton sulla pagina è facoltativa, è una procedura perfettamente valida, diversa dall’uso di onclick anziché di addEventListener (ma probabilmente è una questione di stile). Ovviamente, avresti questo codice in uno script collegato alla fine del documento, appena prima del (o triggersto tramite un callback DOMContentLoaded ).


Ma se vuoi l’equivalente di jQuery, devi pensare nella mentalità “set-based” di jQuery e usare querySelectorAll :

 // Not very efficient document.querySelectorAll("#logInButton").forEach(function() { // Set up the handler here using `this` }); 

Tranne che jQuery ottimizza le query usando il formato #id per una chiamata getElementById (che è drammaticamente più veloce) e poi usa un if (come il tuo) per build il set con un elemento o zero.

Forse nella tua ricerca di non usare jQuery, potresti darti un paio di funzioni di supporto per prendere il suo posto, poiché l’API DOM è abbastanza dettagliata. Se ti piace la natura basata su set di jQuery, potresti persino renderli basati su set:

 function MyQuery(selector) { if (!selector) { this.data = []; } else if (typeof selector === "string") { // (jQuery takes it further than this, search in an unminified version for `rquickExpr`) var id = /#([\w-]+)/.match(selector); if (id) { var e = document.getElementById(id[0]); this.data = e ? [e] : []; } else { this.data = Array.from(document.querySelector(selector)); } } else { /* ...handle other things, such as DOM elements or arrays of them...? */ this.data = /*...*/; } } MyQuery.prototype = { constructor: MyQuery, on: function(eventName, handler) { this.data.forEach(function(element) { element.addEventListener(eventName, handler); }); return this; } // ...etc... }; function qset(selector) { return new MyQuery(selector); } 

Poi

 qset("#logInButton").on("click", /*...*/); 

Certo, potresti ritrovarti a ricreare in pratica jQuery. Ma se lo tieni magra …


Nota a forEach : l’uso di forEach sul valore restituito di querySelectorAll richiede un browser aggiornato o lo si inserisce in polipropilene:

 if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) { Object.defineProperty(NodeList.prototype, "forEach", { value: Array.prototype.forEach }); } 

Per i browser veramente obsoleti (come IE8), dovresti polyfill Array.prototype.forEach Prima di tutto.

Puoi farlo nello stesso modo di jQuery, usando il bubbling degli eventi.

 document.addEventListener('click', function (ev) { if (ev.target.id === 'someIdHere') { console.log('click'); } });