Portál AbcLinuxu, 28. března 2024 16:56

BLite.js - Knihovna pro Javascript

24.1.2009 13:58 | Výběrový blog | poslední úprava: 31.8.2009 14:22

Tento blog byl smazán autorem

       

Hodnocení: 100 %

        špatnédobré        

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (3) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Vložit další komentář

24.1.2009 14:55 Vskutečnosti Saýc | skóre: 7
Rozbalit Rozbalit vše Re: BLite.js - Knihovna pro Javascript
Odpovědět | Sbalit | Link | Blokovat | Admin
To je husty. Proc to neni clanek?
24.1.2009 18:06 Leoš Literák | skóre: 74 | blog: LL | Praha
Rozbalit Rozbalit vše Re: BLite.js - Knihovna pro Javascript

Jojo, souhlas, Mame ideu, ze by bylo fajn mit moznost jednoduse primo vydat zapisek jako clanek. Ted to nejde a musi se vydat samostatny clanek.

Zakladatel tohoto portálu. Twitter, LinkedIn, blog, StackOverflow
24.1.2009 14:59 freshmouse
Rozbalit Rozbalit vše Re: BLite.js - Knihovna pro Javascript
Odpovědět | Sbalit | Link | Blokovat | Admin

Mimochodem, nedoporučí někdo nějakou dobrou česky psanou (anglicky psané beru až ve druhém kole -- preferuju češtinu) knihu o JS? Potřebuju se to naučit, takže nechci žádné knížky typu "Naučte se JavaScript a stavět ropné tankery během 5 dní"...

24.1.2009 15:49 pasmen | skóre: 45 | blog: glob | Praha
Rozbalit Rozbalit vše Re: BLite.js - Knihovna pro Javascript

Já mám JavaScript a AJAX od Johna Resiga (tvůrce JS knihovny jQuery), z Cpressu. Doporučuju.

24.1.2009 15:09 Andrej Herceg | skóre: 43
Rozbalit Rozbalit vše Re: BLite.js - Knihovna pro Javascript
Odpovědět | Sbalit | Link | Blokovat | Admin
Pri funkciách BLite.Dom.append a BLite.Dom.prepend by nebolo lepšie (a hlavne rýchlejšie) použiť fragmenty (a teda document.createDocumentFragment())?
24.1.2009 15:24 Deleted [8409] | skóre: 14 | blog: darkblog
Rozbalit Rozbalit vše Re: BLite.js - Knihovna pro Javascript
Ono by to chtělo revizi. BLite.Dom.append() atd neudělají nic, pokud je element null nebo undefined. Toto byl původní návrh, ve kterém jsem byl asi trochu ovlivněn systémem hromadného zacházení s elementy. Jenže časem se stalo to, že tento systém považuji za nedokonalý (pokud chci přidat prvek, tak přece musí existovat).

Jinak document.createDocumentFragment() je pro mě novinka, musím to prozkoumat. Pokud máte řešení jak to přepsat, tak to pošlete nebo vytvořte Issue na stránkách projektu, ať se na to nezapomene.

Koneckonců ke zveřejnění jsem se rozhodl právě kvůli čistce a stabilizaci celého API.
31.8.2009 15:06 backup
Rozbalit Rozbalit vše Záloha: BLite.js - Knihovna pro Javascript
Odpovědět | Sbalit | Link | Blokovat | Admin

Knihovna BLite vznikla jako velice tenká knihovna pro ulehčení práce s javascriptem. První otázka člověka, který se pohybuje v této oblasti určitě bude: "proč další knihovna, když jich jsou desítky" ? Odpověď na tuto otázku je tento zápisek, posuďte sami... (jedná se o dlouhý zápisek)

Úvod

Každý, kdo se zabývá psaním webových stránek, ve kterých je potřeba trochu interaktivity, potřebuje nějakou knihovnu, o kterou se může opřít. Dnes je situace ale taková, že knihovny toho nabízejí mnohokrát víc, než programátor potřebuje, a to se projevuje i na samotné velikosti těchto knihoven. Některé knihovny se snaží pokrýt hodně věcí, a v tom bude asi problém. Na webu se každým dnem setkávám s použitím opravdu velkých knihoven na triviální věci typu skrýt DIV nebo vytvořit nějakou DOM strukturu a přidat ji do kontejneru. Využití velkých knihoven může více zatížit klientské CPU a zpomalit načítání stránek.

Při prozkoumání existujících řešení jsem přišel na to, že žádná knihovna nepokryje moje požadavky. Jediná možnost je kombinovat více knihoven na různé věci, ale u tohoto principu mi vadí nesourodost výsledného kódu a nevyužití mnoha částí těchto knihoven (stejný pohled může mít samozřejmě kdokoliv na BLite).

Filozofie BLite

Knihovna BLite byla navržená s ohledem na konečou velikost výsledého js souboru. Cílem bylo, aby se jednalo o čistě javascriptovou knihovnu (tedy žádné CSS jako např. u YUI) a aby se pomocí této knihovny daly psát jednoduše i složitější skripty.

Základní vlastnosti

Pokročilé vlastnosti

Filozofie

Co v BLite nenajdete

Dokumentace a příklady

Detekce prohlížeče

Detekce prohlížeče je zatím omezená na internet explorer, který si některé věci implementuje po svém. Pro zjištění, zda se jedná o tento prohlížeč existuje objekt BLite.Browser, který obsahuje proměnné IE a OPERA. Tyto proměnné obsahují buď true nebo false (v případě, že se jedná o konkrétní prohlížeč či nikoliv). Obsahuje ještě metodu canvas(), pomocí které můžeme zjistit, zda prohlížeč podporuje tag <canvas>.

// Příklad provedení kódu jen pro IE
if (BLite.Browser.IE)
{
  alert("Jsem IE, nedodržuji standardy");
}
else
{
  alert("Nejsem IE, standardy se snažím dodržovat, ale občas taky něco uklouzne");
}

Spuštění kódu po načtení stránky (DOMReady)

Je vhodné spouštět přídavný javascriptový kód až po načtení stránky, zejména kvůli tomu, že je hotová DOM struktura. Někdy se dá řešit tento problém umístěním skriptu před konec elementu "body". Pro provedení kódu po spuštění kódu se používá funkce BLite.ready(fn), kde fn je funkce, která se má spustit. Funkci BLite.ready() je možné zavolat vícekrát a přiřadit tak více handlerů pro tuto událost.

// Příklad provedení skriptu po načtení stránky
BLite.ready(function()
{
  // tělo skriptu
  alert("Stránka načtená, a proto teď otravuju já");

});

Práce s DOM

Knihovna BLite se snaží usnadnit programátorovi čas a nervy při vytváření a manipulací s DOM. Mezi nejčastější operace je vytváření a zařazování elementů do existující DOM struktury. Pro vytvoření elementu se používá funkce BLite.Dom.create(tag, args) nebo jednoduše BLite.Dom.TAG(args), kde tag je jméno tagu a args jsou atributy elementu. Je možné vytvářet i prvky, kde má IE v některých jiných knihovnách problémy (input tag). Args je mocný parametr, díky kterému je možné přiřadit elementu při vytvoření i události, styly, text, html a další elementy. Mezi největší odlišnost od ostatních patří atribut "as", který bude vysvětlen v příkladech.

// Vytvoření různých elementů
var div = BLite.Dom.DIV({text:"Toto je DIV"});
var span = BLite.Dom.SPAN({html:"<b>Toto je SPAN</b>"});
var a = BLite.Dom.A({href: "http://kobalicek.com", text: "Odkaz"});

// ale také
var div = BLite.Dom.create("div", {text:"Toto je DIV"});
var span = BLite.Dom.create("span", {html:"Toto je SPAN"});
var a = BLite.Dom.create("a", {href: "http://kobalicek.com", text: "Odkaz"});

Jednalo se o velmi jednoduchý příklad, který by se dalo celkem jednoduše vytvořit i pomocí standardizovaných DOM funkcí. BLite ale umožňuje kromě standardních atributů i své vlastní. Nejjednodušší pro vysvětlení je atribut "children". Pomocí tohoto atributu je možné vložit do právě vytvářeného elementu další elementy.

// Vytvoření jednoduché DOM struktury
var dom = BLite.Dom.DIV({
  children: [
    BLite.Dom.DIV({text: "Já jsem první"}),
    BLite.Dom.DIV({text: "Já jsem druhý"}),
    // je možné vytvářet donekonečna
    BLite.Dom.DIV({children: [
      BLite.Dom.DIV({text: "A další div"})
    ]})
    // atd...
  ]
});

Aby toho nebylo málo, je možné při vytváření i přiřadit události.

// Handler pro událost (e = objekt události)
var onclick = function(e)
{
  alert("Klik");
  // zruší výchozí akci
  BLite.Dom.preventDefault(e);
};

// Vytvoření jednoduché DOM struktury s událostí. Po kliknutí na odkaz se provede
// handler, který zabrání výchozí akci (přejít na odkaz)
var dom = BLite.Dom.DIV({
  children: [
    BLite.Dom.A({
      href="#",
      text: "odkaz",
      events: { click: onclick }
    })
    // atd...
  ]
});

Mezi poslední rozšíření patří atribut "style", pomocí kterého lze modifikovat styl vytvořeného elementu. Opět je možné (jako u událostí) zadat více stylů.

// Vytvoření jednoduché DOM struktury s událostí a použití atributu "styles" pro modifikaci stylu
// vytvořeného elementu
var dom = BLite.Dom.DIV({
  children: [
    BLite.Dom.DIV({text: "Já nejsem vidět", styles: {display: "none" }}),
    BLite.Dom.DIV({text: "Já jsem vidět"}),
  ]
});

A to úplně poslední rozšíření je to nejzajímavější. Pomocí atributu "as" je možné asociovat vytvořený element do vybraného objektu (nejedná se o DOM, ale o uchování elementu v nějakém objektu pro snadný přístup). Toto se dá v praxi využít při objektově orietovaném designu aplikace. Zavolá se nějaká funkce, která vrátí objekt i s důležitými prvky. Nejlepší bude asi příklad.

// Příklad pro vytvoření komplexní struktury DOM včetně asociace vytvořených elementů

// Objekt, do kterého chceme asociovat DOM
var object = {};

// BLite dáme najevo, že chceme asociovat elementy k objektu pomocí funkce BLite.begin()
BLite.Dom.begin(object);

// vytvoření DOM struktury
BLite.Dom.DIV({
  as: "container"
  children: [
    BLite.Dom.DIV({as: "header"}),
    BLite.Dom.DIV({as: "body"}),
    BLite.Dom.DIV({as: "footer"})
  ]
});

// je nutné ukončit asociaci pomocí funkce BLite.end()
BLite.Dom.end()

// Nyní objekt "object" obsahuje 4 proměnné, které odkazujou na HTML elementy:
// - container
//   - header
//   - body
//   - footer

// K elementům je možné se kdykoliv dostat:
object.header.style.display = "none";
object.footer.style.display = "none";
object.body.style.color = "black";

// atd...

Doufám, že je popis DOM builderu vyčerpávající. Pokud se použijí funkce BLite.Dom.begin() a BLite.Dom.end(), objekt, do kterého se asociace objektů provádí, je taky kontext (this) handlerů událostí definovaných pomocí atributu "events".

Knihovna BLite obsahuje i další funkce pro manupulaci s DOM. Pro získání elementu podle id existuje funkce BLite.$(id) (jedná se o zkratku pro document.getElementById(id), některé knihovny zkracují až na znak $). Pro navigaci v DOM struktuře slouží tyto funkce:

Pro manipulaci se strukturou slouží tyto funkce:

Práce s událostmi

Pro práci s událostmi existují 2 hlavní funkce, BLite.Dom.addListener() a BLite.Dom.removeListener(). Pomocí první funkce se přidá handler události k určitému elementu a druhá funkce slouží k jeho odstranění. Návrh knihovny BLite je takový, aby bylo možné zadávat i kontext funkce (this) a při stejné kombinaci mít možnost odstranit handler. U jiných knihoven, kde přidání handleru neobsahuje kontext funkce a je nutné použít tzv. bind(), který obalí handler pomocnou funkcí, takto není možné odstranit handler.

// Příklad přidání handleru pro "click" událost

// nějaký objekt, který použijeme jako kontext
var object =
{
  // proměnná
  count: 0,
  
  // nějaký element, a jehož události chceme reagovat
  link: BLite.Dom.A({
    href="#",
    text: "Klikni"
  }),

  // handler
  onclick: function(e)
  {
    // nastaví text odkazu
    BLite.Dom.setText(this.link, "Už jenom " + (10 - this.count) + "x");

    // 10x se klikne na odkaz a handler se odstraní
    if (++this.count >= 10) BLite.Dom.removeListener(e);

    // Zabrání výchozí události
    BLite.Dom.preventDefault(e);
  }
};

// Přidá event handler
BLite.Dom.addListener(object.link, "click", object.onclick, object);

// Stejný způsob pro odebrání
BLite.Dom.removeListener(object.link, "click", object.onclick, object);

Myslím, že nemá cenu víc vysvětlovat. O událostech je možné na internetu hodně přečíst a knihova BLite jen usnadňuje operaci s nimi. Funkce BLite.Dom.preventDefault(e) a BLite.Dom.stopPropagation(e) jsou cross-browser funkce zastavení propagace událostí, které nepodporuje snad jen IE. Mezi další pomocné funkce patří BLite.Dom.eventTarget(e) a BLite.Dom.relatedTarget(e). Opět se jedná o cross-browser řešení drobné nekompatibility mezi IE a zbytkem světa.

Práce s CSS

Pro práci s CSS obsahuje knihovna BLite pár funkcí. Tyto funkce jsou snad ve všech knihovnách tak nemá cenu je moc rozebírat. Jedná se o BLite.Dom.addClass() a BLite.Dom.removeClass() pro přidání a odebrání stylu. K testování, jestli prvek obsahuje css styl souží BLite.Dom.hasClass() a jako zlepšení syntaxe je zde i funkce BLite.Dom.setClass(), která nastaví kompletní className daného elementu.

// Příklad práce s CSS

// nějaký element
var div = BLite.Dom.DIV();

// nastaví CSS třídu
BLite.Dom.setClass(div, "menu");
// přidá CSS třídu
BLite.Dom.addClass(div, "selected");
// odebere CSS třídu
BLite.Dom.removeClass(div, "menu");
// testuje CSS třídu (výsledek je v našem případě true)
alert(BLite.Dom.hasClass(div, "selected"));

AJAX

Podpora AJAXu je v dnešní době velmi důležitá. Knihovna BLite obsahuje funkci BLite.Request.send(), díky které je možné poslat asynchronní dotaz na server. Implementace používá XHTTPRequest nebo ActiveX (IE). Funkce má pouze jeden parametr, a to je objekt, který může obsahovat následující proměnné:

// Příklad poslání požadavku na server a reakci na odpověď ve formátu JSON
BLite.Request.send({
  url: "/url/adresa/",
  method: "POST",
  data: {
    page: 1,
    lang: "cz"
  },
  success: function(req)
  {
    // Úspěch
    alert("Úspěch");

    // Převod odpověďi na JSON
    var json = BLite.Json.decode(req.responseText);
    
    // ...
  },
  failure: function(req)
  {
    // Neúspěch
    alert("Neúspěch");
  },
  context: this
});

Objektově orientované programování

Javascript je sám o sobě objektově orientovaný jazyk, a dalo by se říct, že všechno, kromě primitivních typů, je objekt (i primitivní typ je objekt, ale jiný, než ho chápu já). Když jsem začal používat toolkit qooxdoo, objevil jsem neuvěřitelně flexibilní objektově orientovaný design, který jsem chtěl používat i v tradičních webových stránkách. Vytvořil jsem tedy podobný způsob pro vytváření objektů, jaký obsahuje qooxdoo.

BLite obsahuje funkci pro vytvoření třídy a základní třídu, ze které by měly vycházet všechny ostatní (ale nemusí to být pravidlo). Pro vytvoření třídy se používá funkce BLite.Object.define(classname, map). První parametr je jméno třídy i včetně jmenného prostoru (jako řetězec, třeba "mynamespace.MyClass"), druhý parametr je slovník, který může obsahovat tyto klíče:

Je toho celkem moc, tak se pokusím přiblížit, o co se jedná. Většinou se jako první začíná tím, co rozšiřujeme. K tomu se dá použít klíč extend. Samozřejmostí je, že můžeme použít operátor instanceof pro zjištění, jestli je instance instancí dané třídy. Další výhoda dědičnosti je metoda base() a self(), díky kterým je možné volat statické funkce třídy a funkce, které rozšiřujeme.

Klíče construct a destruct slouží pro implementaci konstruktoru a destruktoru. Konstruktor může obsahovat parametry a volá vždycky předešlý konstruktor. Destruktor je bezparametrická funkce, a nikdy nevolá předešlý desktruktor.

Klíč properties je mapa, která vždy obsahuje klíč (jméno property) a nastavení. Getter a setter bude automaticky vytvořen. Například pro property "label" budou automaticky vytvořené funkce "getLabel()" a "setLabel()". Je možné zadat funkci, která bude zavolána v případě, že zavoláme setter (setLabel) a změníme hodnotu property. Toto bude ukázané na příkladu, kde je možné nejlíp vidět čistotu tohoto designu.

Klíč members obsahuje členské funkce třídy a klíč statics obsahuje statické funkce a proměnné třídy.

// Jednoduchý příklad vytvoření třídy "A" v prostoru jmen "Namespace"
BLite.Object.define("Namespace.A",
{
  // Konstruktor
  construct: function()
  {
    // Nutnost volat předchozí konstruktor
    this.base(arguments);

    alert("Created");
  },
  
  // Členské metody
  members:
  {
    hello: function()
    {
      alert("Hello");
    }
  },
  
  // Statické metody
  statics:
  {
    PI: 3.14
  }
});

// Vytvoření objektu
var a = new Namespace.A();
// volání metod
a.hello();
// použití instanceof (vrátí true)
alert(a instanceof Namespace.A);
// statický prostor
alert(Namespace.A.PI); // 3.14

No není to jednoduché a čísté? Toto je samozřejmě jen špička ledovce. Největší výhody uvidíme při dědičnosti a definování properties. Každá třída vytvořená pomocí BLite.Object.define() může používat uvitř 2 speciální funkce. Jsou to base() a self(). Pomocí funkce base se zavolá zděděná funkce, pomocí funkce self se získá statický prostor třídy (Statický prostor se v javascriptu nedědí, takže třída B, která vychází z třídy A nemůže přistoupit ke statickému prostoru třídy A z třády B).

// Komplexní příklad dědičnosti

// Definice třídy Namespace.A
BLite.Object.define("Namespace.A",
{
  // Rozšiřujeme základní objekt
  extend: BLite.Object,

  // Konstruktor
  construct: function()
  {
    // Nutnost volat předchozí konstruktor
    this.base(arguments);

    alert("Created A");
  },
  
  // Členské metody
  members:
  {
    hello: function()
    {
      alert("Hello A");
    }
  }
});

// Definice třídy Namespace.B, která rozšiřuje Namespace.A
BLite.Object.define("Namespace.B",
{
  // Rozšiřujeme Namespace.A
  extend: Namespace.A

  // Konstruktor
  construct: function()
  {
    // Nutnost volat předchozí konstruktor
    this.base(arguments);

    alert("Created B");
  },
  
  // Členské metody
  members:
  {
    hello: function()
    {
      // Zavoláme hello() z předka
      this.base(arguments);

      alert("Hello B");
    }
  }
});

// Vytvoření objektů
var a = new Namespace.A(); // Created A
var b = new Namespace.B(); // Created A, Created B

// volání metod
a.hello(); // Hello A
b.hello(); // Hello A, Hello B

// použití instanceof
alert(a instanceof Namespace.A); // true
alert(b instanceof Namespace.B); // true

alert(a instanceof Namespace.B); // false
alert(b instanceof Namespace.A); // true

Zbývá vysvětlit poslední věc - properties. Jedná se velké ulehčení práce s javascriptem a objektovým designem obecně. Doporučuji používat funkce get...() a set...(), protože v javascriptu se při překlepu nemusí poznat chyba, kterou můžete ladit i půl dne. Pokud proměnné obalíte do funkcí get() a set(), při překlepu vám vyskočí výjimka a problém okamžitě odhalíte. Definice properties je ukázaná v následujícím příkladě.

// Příklad definování properties

// Definice třídy Namespace.A
BLite.Object.define("Namespace.A",
{
  // Rozšiřujeme základní objekt
  extend: BLite.Object,

  // Konstruktor
  construct: function()
  {
    // Nutnost volat předchozí konstruktor
    this.base(arguments);
    
    // Nastavení properties
    this._id = null;
  },
  
  // Properties
  properties:
  {
    // definice property id, automaticky vygeneruje metody getId() a setId(id).
    // apply slouží k aplikaci změny property. Bude zavolána z funkce setId(id),
    // ale pouze v případě, že došlo ke změně
    //
    // každá property je v instanci reprezentována jako _jméno, v našem případě
    // to bude tedy _id.
    id: { apply: "_applyId" }
  },
  
  // Členské metody
  members:
  {
    _applyId: function(id, old)
    {
      // Změna už byla provedená...
      alert("Změna id na " + id + " z " + old);
    }
  }
});

// Vytvoření objektu
var a = new Namespace.A();

// Můžeme použít metody getId() a setId()
alert(a.getId()); // null
alert(a._id);     // null

// nastavit property, tato funkce zavolá _applyId, protože se hodnota změní
a.setId(1); // alert, změna id na 1 z null

alert(a.getId()); // 1
alert(a._id);     // 1

a.setId(2); // alert, změna id na 2 z 1

// to není všechno, k properties lze přistupovat pomocí get() a set() metod
a.set("id", 10) // alert, změna id na 10 z 2
a.get("id"); // 10

// metoda set() se může také využít k hromadnému nastavení více hodnot:
a.set({
  id: 20
  // ...
});
// alert, změna id na 20 z 10

Závěr

Knihovna BLite.js je určená pro programátory, které zajímá mnohem víc design a čistota kódu, než nějaké hromadné přidávání událostí do X odkazů na stránce. Umožňuje pracovat s DOM a událostmi + vytváří pokročilý objektově orientovaný design vašeho kódu. Možnost vytvořit vlastní třídy a přidávat plnohodnotné handlery událostí (včetně this) jsou jedny ze základních kamenů celé knihovny.

Objektově orientované programování pomocí BLite.Object.define() bylo inspirováno v toolkitu qooxdoo, který je podle mě jeden z nejlepších pro vývoj webových aplikací (ale nevhodný pro standardní webové stránky). Knihovna BLite vznikla hlavně z důvodů, aby bylo možné psát velmi podobný kód pro tradiční html stránky a webové aplikace v qooxdoo.

Statistika

Číselné údaje knihovny BLite.js.

Nejste spokojení? Existují i další knihovny

Poznámky

Zdroj

Knihovnu BLite je možné stáhnout na http://code.google.com/p/blite/ a šířit pod MIT licencí.

Opravy v článku:

Založit nové vláknoNahoru

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.