Javascript-utveckling, my take
Att utveckla JavaScript är en balansgång på brinnande lina. JavaScript kan göra fantastiska skillnader i användbarhet, och ingen ska vara rädd för att neka sina webbapplikationer sådant. Samtidigt är kraven på kvalitet högre än någonsin: Genvägar kan göra googles spindlar ledsna, script som inte fungerar i vissa webbläsare skapar frustration och missämja, och långa laddningstider är det aldrig någon som gillat.
Jag tänkte därför mycket kort skriva ner mina JavaScript-vanor, i hopp om att det hjälper någon.
Först: hur det inte ska se ut
När JavaScript googlas på innehåller många nybörjartutorials nedanstående exempel.
-
Tjohej!
-
Tjohej!
-
<form action="" onsubmit="foobar()"> ... </a>
-
<input type="text" onchange="foobar()">
-
// och så vidare
Det är sorgligt att sådana dåliga exempel ska synas mest för alla som
vill lära sig göra häftiga webbplatser. Länkar med felaktigt href
(protokollet javascript
existerar inte) gör googles spindlar
förvirrade och kan påverka sökplaceringar i större omfattningar. Bland
webbutvecklare är det sett som dålig sed att använda style
-attributet
på HTML-element, för att det skapar spaghettikod och blir svårare att
hantera i långa loppet. Av samma skäl hör varken onclick
, onchange
eller liknande hemma i HTMLdokument.
Lugn, det finns bättre!
Det jag talar om är en filosofi som heter Unobtrusive JavaScript, som grovt går ut på att gränssnitt har tre lager:
Semantik och disposition av innehåll : HTML och XHTML
Presentation och design : CSS
Interaktivitet och respons : JavaScript
JavaScript är ett lager i sig självt, som ska arbeta fristående från de andra två (undre) lagren. Rent praktiskt ser det ut så här:
-
window.onload = function()
-
{
-
var lnk = document.getElementsByTagName('a');
-
lnk.onclick = foobar;
-
-
var frm = document.getElementsByTagName('form');
-
frm.onsubmit = foobar;
-
-
var inpt = document.getElementsByTagName('input');
-
inpt.onchange = foobar;
-
}
Det enda spåret vi ser av detta är en script
i head
:
-
<html>
-
<head>
-
<title>Exempelsida</title>
-
...
-
<script src="foobar.js" type="text/javascript"></script>
-
</head>
-
...
-
<html>
Hemligheten ligger i window.onload
. Den körs varje gång en sida har
laddats. Det ovanstående kod gör är att leta upp HTML-element via
DOM och
tilldela dessa händelselyssnare. Det finns otaliga bättre sätt att göra
det på än jag gör, men principen är densamma: JavaScript initieras av
JavaScript, ej av HTML.
Tjästestrukturerade script
Med ovanstående i åtanke kan jag gå vidare med hur jag brukar göra för att enkelt kunna hitta i mina (till slut gigantiska) JavaScript-filer. Jag börjar alltid med att skissa på vad jag ska scripta, och delar in dessa i tjänster och delade egenskaper.
Tjänst : Kan vara en blogg, kontaktsida, kalender eller något annat som
bildar en del av ett dokument.
Delade egenskaper : Kan vara toggle-funktioner, tooltips, formulärwidgets eller annat
som delas av flera tjänster.
Utifrån det använder jag JavaScriptobjekt för att skapa egna scopes. Ett typiskt objekt brukar se ut så här för mig:
cn (objekt) : Står för \”classnames\”, men innebär mer än så. Här skriver jag upp
alla klassnamn, id och elementnamn som jag behöver för att söka
igenom DOM-trädet. När jag vill ha bloggens wrapper (omslutande
element) skriver jag `this.cn.wrp` eller `Blog.cn.wrp`.
labels (objekt) : Om jag skapar nya element med script, ska länktexter, knapptexter et
cetera stå här för att underlätta hantering.
Exists (function : bool) : Funktionen letar igenom DOM-trädet efter instanser av tjänsten, och
returnerar en bool (sant/falskt).
init (function : void) : Applicerar script på tjänsten.
-
var Blog = new Object();
-
Blog.cn = new Object();
-
Blog.cn.wrp = "blogWrapper";
-
Blog.cn.wrp = "blogEntries";
-
Blog.labels = new Object();
-
Blog.labels.toggle = "visa hela";
-
Blog.exists = function(){ //finns? };
-
Blog.init = function(){ //starta };
Jag föredrar dock istället kortvarianten för att det är mer läsbart:
-
var Blog = {
-
cn : {
-
wrp : "blogWrapper",
-
entry : "blogEntries"
-
},
-
labels : {
-
toggle : "visa hela"
-
}
-
exists : function(){
-
//finns?
-
},
-
init : function(){
-
//starta
-
}
-
}
Till detta kompletterar jag med en funktion som brukar ha \”prepare\” som prefix, en sk invoke:
-
window.onload = function() {
-
prepareBlog();
-
};
-
-
function prepareBlog() {
-
if(Blog.exists()) {
-
Blog.init();
-
}
-
}
I den anonyma funktionen läggs alla tjänsters invokes efter varandra för
att exekvera på sidan. Ett annat sätt är att låta Blog.init
köra
Blog.exists
internt och avbryta om falskt istället för att skapa en ny
funktion för det, men det är som man själv vill.
Nog för idag
Jag är inte riktigt färdig ännu. Det återstår litet pill till innan jag är klar med mina rutiner. Mer om detta kommer i en senare blogg om ämnet.
Vidare läsning
- Progressive Enhancement och Graceful Degradation.
- DOM scripting av Jeremy Keith, en bok om javascript på rätt sätt.
- Simply JavaScript av Cameron Adams och Kevin Yank, en annan bok om javascript på rätt sätt.