Come funziona Javascript inline (in HTML)?


129

So che questa è una cattiva pratica. Non scrivere codice come questo, se possibile.

Naturalmente, ci troveremo sempre in situazioni in cui un frammento intelligente di Javascript inline può risolvere rapidamente un problema.

Sto perseguendo questa domanda nell'interesse di comprendere appieno cosa succede (e le potenziali insidie) quando viene scritto qualcosa del genere:

<a href="#" onclick="alert('Hi')">Click Me</a>

Per quanto posso dire questo è funzionalmente uguale a

<script type="text/javascript">
   $(function(){ // I use jQuery in this example
       document.getElementById('click_me').onclick = 
           function () { alert('Hi'); };
   });
</script>
<a href="#" id="click_me">Click Me</a>

Estrapolando da ciò sembra che la stringa assegnata all'attributo onclicksia inserita all'interno di una funzione anonima assegnata al gestore di clic dell'elemento. È davvero così?

Perché sto iniziando a fare cose del genere:

<a href="#" onclick="$(this).next().fadeIn(); return false;">Display my next sibling</a> <!-- Return false in handler so as not to scroll to top of page! --> 

Che funziona Ma non so quanto sia un hack questo. Sembra sospetto perché non vi è alcuna funzione apparente che viene restituita!

Potresti chiedere, perché lo stai facendo, Steve? Inline JS è una cattiva pratica!

Beh, ad essere sincero, sono stanco di modificare tre diverse sezioni di codice solo per modificare una sezione di una pagina, specialmente quando sto solo prototipando qualcosa per vedere se funzionerà affatto. È molto più semplice e talvolta ha persino senso che il codice specificamente correlato a questo elemento HTML sia definito proprio all'interno dell'elemento: quando decido 2 minuti più tardi che questa è stata un'idea terribile e terribile, posso annusare l'intero div (o qualunque cosa ) e non ho un mucchio di misteriose cruft JS e CSS in giro nel resto della pagina, che rallentano leggermente il rendering. Questo è simile al concetto di località di riferimento, ma invece di errori nella cache stiamo osservando bug e code bloat.


3
Hai ragione, è una funzione anonima.
bhamlin,

1
Sarà necessario agganciare la query #click_meall'evento DOMready o posizionare lo script dopo il nodo.
Bergi,

1
In una console, fallo document.getElementById("click_me").onclick;. O avvisalo. Vedrai che è in una funzione.
D. Strout,

Risposte:


96

Hai quasi ragione, ma non hai tenuto conto del thisvalore fornito al codice inline.

<a href="#" onclick="alert(this)">Click Me</a>

è in realtà più vicino a:

<a href="#" id="click_me">Click Me</a>
<script type="text/javascript">
document.getElementById('click_me').addEventListener("click", function(event) {
    (function(event) {
        alert(this);
    }).call(document.getElementById('click_me'), event);
});
</script>

I gestori di eventi inline impostati sono thisuguali al target dell'evento. Puoi anche usare la funzione anonima nello script inline

<a href="#" onclick="(function(){alert(this);})()">Click Me</a>

7
Lo script deve venire dopo il tag, altrimenti il ​​tag non esiste quando viene eseguito - ti suggerisco di cambiare la tua risposta per riflettere questo.
indefinito

come faccio a propagare il eventcon un inline onclick='myFunction(event)'??
Oldboy

9

Cosa fa il browser quando hai

<a onclick="alert('Hi');" ... >

consiste nell'impostare il valore effettivo di "onclick" su qualcosa come:

new Function("event", "alert('Hi');");

Cioè, crea una funzione che prevede un parametro "evento". (Beh, IE no; è più come una semplice funzione anonima semplice.)


2
Ah. Quindi posso effettivamente utilizzare la variabile eventper recuperare l'evento (e l'elemento di origine da esso tramite event.target), dal mio frammento JS in linea! Freddo.
Steven Lu,

1
IE in realtà non passa il eventparametro, ma se si utilizza eventall'interno di questa funzione anonima IE lo capirà come l'oggetto evento effettivo. Poiché la funzione anonima viene impostata come proprietà windowdell'oggetto in IE, verrà visualizzato come window.event.
rdleal,

8

Sembra che ci siano molte cattive pratiche lanciate attorno agli attributi del gestore eventi. La cattiva pratica non è conoscere e utilizzare le funzionalità disponibili dove è più appropriato. Gli attributi degli eventi sono standard completamente documentati dal W3C e non vi è nulla di negativo. Non è diverso dal posizionare stili in linea, che è anche documentato W3C e può essere utile in tempi. Che tu lo inserisca avvolto in tag script o meno, verrà interpretato allo stesso modo.

https://www.w3.org/TR/html5/webappapis.html#event-handler-idl-attributes


2
Sì, sono propenso a concordare e ho anche fornito ragionevoli "ragioni" per cui questo particolare tipo di utilizzo del codice inline potrebbe essere giustificato in determinate situazioni. Ma la realtà è che quando un'app (app Web o altro) diventa una certa complessità (e questo di solito non richiede nemmeno molto tempo o lavoro per raggiungere) avere piccoli frammenti di codice sparsi sul layout HTML è probabile che essere architettonicamente insensato dal punto di vista della manutenibilità. Cominciando persino a codificare direttamente JS all'interno di un file HTML, ad esempio, si è tentati la pendenza scivolosa della spaghettificazione.
Steven Lu,

1
E questo è un valido argomento valido contro, su cui sono d'accordo. Normalmente non aggiungo script in linea, né lo stile per quella madre, me stesso. Ma le persone hanno gusti diversi. Molti, ad esempio, amano aggiungere script e tag di stile nella sezione del corpo, non lo sopporto. Ma è valido e ad alcune persone piace. Ciò che piace bad practice/spaghettificationper alcuni è good practice/structureper altri.
Daniel B,

Ho esaminato github.com/styled-components/styled-components e se lo combini con la reazione, ad esempio, ora abbiamo tutto ciò che è associato a un componente della tua app che vive effettivamente (speriamo pacificamente) in un unico posto. E in realtà non sembra neanche terribile. Sembra un progresso. In questa luce, il jamming di stili e code incorporati in HTML non è il modo giusto (finora sembra essere il jamming di HTML e stili nel codice JS).
Steven Lu,

5

Il modo migliore per rispondere alla tua domanda è vederlo in azione.

<a id="test" onclick="alert('test')"> test </a> 

Nel js

var test = document.getElementById('test');
console.log( test.onclick ); 

Come vedi in console, se stai usando Chrome, stampa una funzione anonima con l'oggetto evento passato, anche se è un po 'diverso in IE.

function onclick(event) {
   alert('test')
}

Concordo con alcuni dei tuoi punti sui gestori di eventi inline. Sì, sono facili da scrivere, ma non sono d'accordo con il tuo punto di dover cambiare codice in più punti, se strutturi bene il tuo codice, non dovresti aver bisogno di farlo.


Penso che qualcosa del genere <button onclick="login()"> test login </button>vada benissimo per la prototipazione. Vuoi testare qualcosa che richiede l'interazione dell'utente in questo momento e lo eliminerai comunque in seguito. Perché scrivere codice aggiuntivo in tutto il luogo?
Dagg Nabbit,

Non è un codice aggiuntivo, solo una funzione anonima aggiuntiva. E non è dappertutto, in realtà è tutto in un posto, nei tag dello script.
Aziz Punjani,

Non sono sicuro che condividiamo la stessa idea di "strutturare bene il tuo codice". Se associ l'interfaccia utente alle tue "funzioni principali" nel luogo in cui vivono effettivamente le tue funzioni principali, questo mi sembra una disposizione di accoppiamento peggiore rispetto al semplice vincolarli nell'interfaccia utente. Di solito tengo tutte le cose vincolanti dell'interfaccia utente separate da quelle fondamentali e ho la sensazione che anche l'OP potrebbe ...
Dagg Nabbit,

3

Sembra sospetto perché non vi è alcuna funzione apparente che viene restituita!

È una funzione anonima che è stata associata all'evento click dell'oggetto.

perché lo stai facendo, Steve?

Perché diavolo stai facendo ..... Ah non importa, come hai già detto, è davvero una cattiva pratica ampiamente adottata :)


3

Prova questo nella console:

var div = document.createElement('div');

div.setAttribute('onclick', 'alert(event)');

div.onclick

In Chrome, mostra questo:

function onclick(event) {
  alert(event)
}

... e la nameproprietà non standard di div.onclickis "onclick".

Quindi, se questo è anonimo dipende dalla tua definizione di "anonimo". Confronta con qualcosa di simile var foo = new Function(), dove si foo.nametrova una stringa vuota, e foo.toString()produrrà qualcosa di simile

function anonymous() {

}

Questo è iniziato come un commento sulla risposta di Pointy, ma in realtà non ha funzionato come un commento. La sua è davvero la migliore risposta qui, credo.
Dagg Nabbit,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.