Abro, Juli 2010

jQuery – Die Kunst es jeden Tag ein bisschen besser zu machen

Oder: Wie ich erst lernen musste
mir besser in den Fuß zu schießen

Nach so langer Zeit der Abstinenz bin ich wohl wieder in Zugzwang etwas hilfreicheres niederzuschreiben, als mein “ich wunder mich” des Tages. Warum also nicht mal mit dem Trend gehen und euch als jQuery Fanatiker mit dem unterhalten, was ich in der Developer Community des Frameworks erst nach und nach lernen musste.

Bei jQuery ist aller Anfang einfach. Schaut man nach 3,4 Monaten aber auf seinen Code zurück, so gibt es doch immer eine ganze Menge verbesserungswürdiges. Nicht jeder heisst John ResigRyan Florence oder Karl Swedberg. Und das ist auch gut so.

An dieser Stelle liegt mein Hauptfokus nicht darauf das letzte Fitzelchen Performance aus dem Source zu quetschen. Es geht viel mehr darum kein Cargo Cult Programming zu betreiben und sich vielleicht ein bisschen eleganter in den Fuß zu schießen als zuvor ;) .

Hier kommt jQuery für’s Langzeitgedächtnis

Variablen

  • Vergesst “var” nicht, haltet euren Global Namespace sauber.
    Das macht auch die Ausführung etwas schneller.

    1
    2
    3
    4
    5
    6
    7
    
    foo = 1;
    function bar()
    {
      foo = 2;
    }
    bar();
    alert(foo); //2

    vs

    1
    2
    3
    4
    5
    6
    7
    
    var foo = 1;
    function bar()
    {
      var foo = 2;
    }
    bar();
    alert(foo); //1
  • 1x var reicht. Das ist auch oft Codingkonvention.
    (Tipp: Validieren mit jsLint.)

    1
    2
    
    var $p = $('p'),
        y  = $p.height();
  • Wie oben schon zu sehen stelle ich jeder Variable ein “$” voran, wenn sie ein jQuery Objekt enthält. Das macht den Code meiner Ansicht nach extrem übersichtlich.

Funktionen

  • Auch anonyme Funktionen helfen den Namespace sauber zu halten und Konflikten vorzubeugen. Wir alle kennen z.B. eine ganze Palette an Wrappern, in die dann der JS-Code herein kommt. Aber welcher Wrapper ist denn nun wofür der richtige? Meine Empfehlung:

    Für Plugins und alle Dinge, die nicht von *.ready abhängig sind:

    1
    2
    3
    4
    
    (function($)
    {
      //source
    })(jQuery);

    Für den meisten anderen Source – statt $(document).ready():

    1
    2
    3
    4
    
    jQuery(function($)
    {
      //source
    });

Fremder Leute Eigentum heile lassen

  • Don’t break the Chain. Man sollte in jedem jQuery-Plugin immer “this” zurück geben, damit der Plugin-Benutzer nach Aufruf noch weitere Befehle anfügen kann kann.

    1
    2
    3
    4
    5
    
    jQuery.fn.myPlugin = function()
    {
      //do something...
      return this; //!!
    }
  • Don’t break the BackButton. “location.replace()” Legt keinen Eintrag in der Browser-History an. Das kann nur selten gewünscht sein, z.B. bei Framebreakern.

    1
    2
    
    location.replace( $('a').attr('href') ); //badong!
    location.href = $('a').attr('href'); //goood boy
  • Popups sind definitiv richtig böse und window.open ist hört sich schon ziemlich nach Popup an, oder? Also lasst die Methode einfach ganz weg. Einzig legitimer Weg um neue Fenster zu öffnen:
    1
    2
    3
    
    $('a[rel~="external"]').click(
      function(){ this.target='_blank'; }
    );

Heile gelassen werden – Fallstricke, Bugs und Verbote

  • Gelegentlich machen die CSS Attribute Probleme,
    lieber gleich immer die JS Schreibweise verwenden.

    1
    2
    
    $el.animate({'margin-top':'10px'},400); //fails in v1.3.2
    $el.animate({'marginTop':'10px'},400);  //works
  • Das Event img.load() feuert in den meisten Browsern beim zweiten Aufruf der Seite nicht, denn die Bilder liegen bereits im Cache. Der Ausweg dazu:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    var browser_is_ie6 = (jQuery.browser.msie && parseInt(jQuery.browser.version) === 6);
    $('img').one('load',function()
    {
      //do sth. with img
    })
    .each(function()
    {
      if( this.complete || browser_is_ie6 )
      {
        $(this).trigger('load');
      }
    });
  • Normale AJAX-Requests an fremde Domains, Subdomains oder Protokolle funktionieren in JS generell nicht. Die Browser verbieten das (“Same origin policy”). Anfragen vom Typ “Script” oder “JSONP” sind davon aber nicht betroffen.
  • In jQuery 1.4 muss der JSON-Input valide sein, wenn er geparst werden soll. Versteht sich eigentlich von selbst, doch die Fehlersuche kann bei so etwas schon ziemlich nerven. Also am besten das JSON immer nur von PHP & Co. generieren lassen und nicht händisch umschreiben, um auf der sicheren Seite zu sein.
  • Das herumpinseln in mehr oder weniger sicherheitssensitiven Elementen wird einem absichtlich schwer gemacht. So auch beim Austauschen von Input[type=password] mit Input[type=text].
  • Ein weiterer großer Fallstrick ist die Userinteraktion. Wer weiss schon was unsere lieben Besucher wann machen und auf welche irren Ideen die kommen. jQuery Frontends fordern halt zum herumspielen auf. So kann es bei schnellem mouseover & -out passieren, dass Animationen nicht zuende geführt werden oder sich aufstauen und minutenlang weiterlaufen. Meine Empfehlungen:

Selektoren

  • var $me = $(this); lohnt sich ab 3x Benutzung.
  • $(‘a’,this) ist wesentlich cooler als $(this).find(‘a’)
    und liefert genau das gleiche Ergebnis.
  • Elternelemente finden geht oft besser als man meint.

    1
    2
    
    $el.parent().parent().parent('.wrapper'); //stupid
    $el.closest('.wrapper') // ^-^
  • Inhalt in iframes kann man benutzen.

    1
    2
    
    var iframe = $('iframe').contents();
    $("p",iframe).slideUp();

jQuery.Novize – Die wichtigsten Optimierungen

Seid lieb zu jQuery, seid sparsam.

  • Select Once.

    1
    2
    3
    4
    5
    
    var $el = $('ul');
    for(i=0; i < 1000; ++i)
    {
      $el.append('<li>Item '+ i +'</li>'); //(s.u!)
    }
  • Wirklich – select once, nutzt die Chain. Wenn man .end() verstanden hat kann man Endlosketten bauen und die Lookups im DOM auf ein Minimum reduzieren.
  • Append Once.

    1
    2
    3
    4
    5
    6
    
    var html = '';
    for(i=0; i < 1000; ++i)
    {
      html += '<li>Item '+ i +'</li>';
    }
    $('ul').append(html);
  • Nicht stehen bleiben – Es gibt immer wieder tolle neue Features und Funktionen. So hat jQuery 1.4 uns den sparsameren Gebrauch von .each() beschert. Fast alles kann jetzt ein Callback ausführen.
    1
    2
    3
    
    $('h4').text(
      function(i,txt){ return txt + ' - nifty!'; }
    );

jQuery.Ninja – Besser, bequemer, 1337er

  • Durch die Chain ist in Plugins “this” schon das jQuery Object $(this).

    1
    2
    3
    4
    5
    6
    
    jQuery.fn.myPlugin = function()
    {
      return this.css('color','red');
    }
     
    jQuery('h2').myPlugin();
  • Bestehende jQuery Funktionen kann man überschreiben.

    1
    2
    3
    4
    5
    6
    7
    
    jQuery.fn.text = function(p1,p2)
    {
      return this.each(function()
      {
        //...
      });
    }
  • Man kann eigene Selektoren anlegen. (Wird intern eher Filter genannt.)

    1
    2
    3
    4
    5
    6
    7
    
    jQuery.expr[':'].containsi = function(el, i, match)
    {
      return (el.textContent || el.innerText || '').toLowerCase()
             .indexOf((match[3] || '').toLowerCase()) >= 0;
    };
     
    jQuery('li:containsi("Eigene Selektoren Anlegen")').css('color','orange');
  • Natives JS hat aufgrund der leichtgewichtigkeit oftmals mehr Sexappeal als den Umweg über jQuery-Funktionen zu gehen.

    1
    2
    
    $('a').attr('title','Lucido Media');
    $('a')[0].title = 'Lucido Media';
  • Kreativ sein! Funktionen missbrauchen kann Nerven sparen.

    1
    2
    3
    4
    5
    6
    
    var obj = {};
    '"11xfoo","12xbar","13xbaz"'.replace(
      /(\d+)x(\w+)/g,
      function(m,val,key){ obj[key] = val; }
    );
    //>>Object foo=11 bar=12  baz=13

JS.Helferlein()



Ein kreativer Kommentar

  1. Kojak, 05.04.2011 10:30h

    Ich könnte mich über deine Beiträge schrott lachen…aber ich muss erstmal weiter arbeiten :))

Kommentare sind geschlossen.
Aufgrund interner Umstrukturierungsmaßnahmen ist es uns z.Zt. leider nicht
möglich auf neue Kommentare zu reagieren. Wir bitten dies zu entschuldigen.
Bei dringenden Rückfragen suchen Sie bitten den direkten Kontakt zu uns.
Das Unternehmen Lucido Media GbR wurde am 31.12.2013 stillgelegt. Diese Website existiert weiterhin zu Archivzwecken. Der Gesellschafter Daniel Abromeit führt seine Arbeit ab sofort unter dem Dach der Agentur Koch Essen fort. Für entsprechende Anfragen wenden Sie sich daher bitte an http://koch-essen.de/kontakt/