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.
Categories: Frameworks, JavaScript, Prototype, Web Development ~ ~ Trackback


February 4th, 2008 at 3:54 am
[…] http://www.milfont.org/tech/2007/10/13/funcao-dollar-do-prototype-para-capturar-elementos-html/ […]
February 9th, 2008 at 2:21 pm
Hum…eu tentei fazer isso…mas o prototype só funciona se vc instanciar com o “new”.
February 10th, 2008 at 3:45 am
Edu, a função dollar “$” está disponível ao acrescentar o script do prototype sem a necessidade de instanciação de qualquer novo objeto. Como você fez que não funcionou?
February 10th, 2008 at 5:44 am
Oi Christiano, eu tentei simplificar ao máximo para eu entender o conceito.
function $(id){
var obj=document.getElementById(id)
return this
}
Tentei adicionar um método por prototype:
$.prototype.color=function(cor){obj.style.color=cor}
Na hora de chamar a função: $(”caixa”).color(”blue”), dava erro:
“objeto não dá suporte ao método”. Ou seja, não existe o método.
Quando eu colocava o método “color” dentro do corpo da função funcionava . Mesmo quando eu testei na base do copy & paste seu código não funcionou, dava o mesmo erro.
Eu queria saber como não conheci seu blog antes…Seu blog é daqueles que eu considero “chato” porque tem tanta coisa interessante que a gente se perde…rsrsrs
Ganhou um leitor assíduo rsrs
Abraço
February 10th, 2008 at 12:20 pm
Ah, agora entendi! Pensei que você estava se referindo ao Framework Prototype.
Se voce acrescentar o script dele na sua página diretamente, verá que funciona -> http://www.prototypejs.org/assets/2008/1/25/prototype-1.6.0.2.js
Qual o segredo aqui, antigamente eles faziam assim:
1 - definiam uma função privada ao escopo do script chamada de function _$() {…}
2 - retornava uma instância dessa função referenciada à variável $.
Observe o update que fiz no post.
February 10th, 2008 at 4:45 pm
Agora simmm!!! Entendi!!!!
Muito interessante isso. Olha se vc for mesmo destrinchar os frameworks vai ser muito bom!! Vai ser muito interessante e didático.
Uma referência assim seria até agora inédito, acho, já que não vi ninguém fazer.
Abraços