Enquanto não preparo um material exclusivo sobre manpulação DOM da especificação W3C, gostaria de falar sobre o encapsulamento dessas operações que os Frameworks Javascript fazem.
A funcionalidade principal de todos os Frameworks, é abstrair a complexidade da manipulação DOM, que não é tão complexa assim mas é chata para muitos. Como o DOM é o acesso aos elementos, e dependemos deles para montar a UI (User Interface) das aplicações, todos (Frameworks) tentam minimizar ou associar essa manipulação com a facilidade de linguagens UI que temos costume no desktop.
O Extjs por exemplo, tem o objeto Ext.Element que representa um elemento DOM e possui métodos amigáveis como: Ext.get(id), para capturar um elemento, Ext.get(”my-div”).setWidth(100) para setar uma largura de 100 pixels a um elemento capturado, entre outros métodos.
O Bruno Torres em seu projeto, O Básico da web, escreveu um artigo básico sobre captura de elementos HTML. Esse artigo me inspirou a falar sobre a função $ (Dollar) famosa no Framework Prototype pela simplicidade. Quem quiser aprender como se seleciona um elemento DOM, dê uma olhada no artigo, lá está bem explicado e com uma didática legal.
A função $ (Dollar), símbolo do uso do Prototype, representa um mecanismo “conveniente” de captura de um elemento, presenteado com métodos auxiliares para a manipulação do DOM em um lote de elementos.
Para capturar o elemento DOM, você precisa usar a sintaxe:
var el = document.getElementById("id_elemento");
A partir daí podemos selecionar ou alterar suas propriedades como:
alert(el.innerHTML); // exibe o conteúdo
Enquanto no Prototype, a função $ providencia um acesso mais limpo:
var el = $("id_elemento");
Essa função é amada por todos os desenvolvedores javascript, a construção dela é absolutamente simples:
function $(els) { this.elements = []; for (var i=0; i < els.length; i++) { var element = els[i]; if (typeof element == 'string') { element = document.getElementById(element); }; this.elements.push(element); }; return this; };
O código da função acrescenta os elementos passados como parâmetros (caso queira capturar vários, apenas separe por vírgula) em uma propriedade array na função. Caso o parâmetro seja uma String, um elemento é capturado pela forma tradicional usando essa String (que deve ser referência a um ID) e acrescentado no array, a cláusula return devolve o escopo da própria função.
A função $ é enriquecida com funçõse que manpulam esse conjunto de elementos. A lógica é que ao retornar esse elemento(s), uma função seja acionada e manipule esse elemento (ou conjunto deles). Essas funções podem ser adicionadas via prototype (propriedade herdada da Global que representa o escopo interno de todos os objetos):
$.prototype = { each: function(fn) { for ( var i=0,len=this.elements.length;i++) { fn.call(this, this.elements[i]); }; return this; } }
Assim, ao selecionar vários elementos, podemos aplicar essas funções diretamente. Outras funções podem ser adicionadas usando o prototype, criando um ecosistema elementar para manipulação desses elementos.
Veja como a aplicação dessa função reduz o código necessário para acionarmos um elemento diretamente e aplicarmos uma instrução que se feita por DOM, levaria várias linhas:
$('botao').on('click', function() { $('teste').each( function(el){ alert(el.value); }); alert($('teste').value); }); }
Nos próximos posts, destilaremos vários frameworks e como cada um faz sua manipulação.
[UPDATE 10-02-2008]
Para exemplificar melhor como trabalha o Framework Prototype, Devido aos comentários do Edu, ficou faltando código para compreender como a função “$” está disponível no código.
Nas versões antigas do framework, eles faziam assim:
- Cria-se uma função privada no contexto referenciada por _$;
- Retorna uma instãncia dessa função _$ referenciada a $;
Como fica isso em código:
// função privada com o código que vimos nesse post function _$(els) { this.elements = []; for (var i=0; i<els.length;> var element = els[i]; if (typeof element == 'string') { element = document.getElementById(element); }; this.elements.push(element); }; return this; }; </els.length;>
Cria a função global “$” com referência a uma instância da função privada “_$”
$ = function() { return new _$(arguments); };
O código completo ficaria assim:
(function() { function _$(els) { this.elements = []; for (var i=0; i<els.length; i++) { var element = els[i]; if (typeof element == 'string') { element = document.getElementById(element); }; this.elements.push(element); }; return this; }; _$.prototype = { each: function(fn) { for ( var i = 0, len = this.elements.length; i<len; ++i ) { fn.call(this, this.elements[i]); }; return this; }, setStyle: function(prop, val) { this.each(function(el) { el.style[prop] = val; }); return this; }, addClass: function(className) { this.each(function(el) { el.className += ' '+className; }); return this; }, css: function(o) { var that = this; this.each(function(el) { for (var prop in o) { that.setStyle(prop, o[prop]); }; }); return this; } }; $ = function() { return new _$(arguments); }; }());
Observe que hoje ficou bem mais rebuscado no código das últimas versões, mas o conceito é o mesmo.
Posted in Frameworks, JavaScript, Prototype, Web Development ~ 6 Comments

