tadarank afiliados

21 dezembro, 2011

QuerySelector ou CSSQuery para IE 6 e 7 (e outros navegadores antigos)

Nobres colegas scripteiros, no maravilhoso mundo da programação, a cada dia a gente se surpreende.

Ontem, durante a programação do Mwords, eu procurava um script de CSSQuery para poder permitir que os usuários do Mwords, escolhessem o elemento alvo com base em seletores CSS. Exemplo: alvo = '#content .post p'.

Lindo né? Assim como no jQuery e outras libs por aí.

As versões que eu achei eram gigantescas (mais de 10k) e a mais recomendada era a do Dean Edwards.
Nunca que eu iria pesar o script do Mwords com 10k só pra ter uma funcionalidadezinha dessas a mais.

Além disso, a maioria dos navegadores modernos já suporta a document.querySelectorAll que permite fazer isso.
O único problemático (pra variar) é o IE (acho que do 8 pra baixo).

Não desisti da minha busca, e acabei encontrando esta pérola da gambiarra feita pelo pessoal do Ajaxian. Funciona maravilhosamente bem e é maravilhosamente pequeno. Um achado digno de glórias ao pessoal do Ajaxian.

Rapidamente adaptei na minha lib, pra usar isto, caso o navegador não suporte a document.querySelectorAll.

Vejam como ficou:

cssQuery = function(sel){ //document.querySelector. sel é o seletor CSS
  //by Micox - http://elmicox.blogspot.com
  var i, res, dqs, d=document;
  if (d.querySelectorAll){
    return d.querySelectorAll(sel);
  }else{ //o IE8 pra baixo e FF 3.5 pra baixo não tem querySelector
    //baseado no fudido script de querySelector do ajaxian http://ajaxian.com/archives/creating-a-queryselector-for-ie-that-runs-at-native-speed
    var head = d.documentElement.firstChild;
    var styleTag = d.createElement("STYLE");
    head.appendChild(styleTag);
    dqs = d.__qsResult = [];

    styleTag.styleSheet.cssText = sel + "{x:expression(document.__qsResult.push(this))}";
    window.scrollBy(0, 0);
    head.removeChild(styleTag);

    res = [];
    for (i in dqs){if (dqs.hasOwnProperty(i)) {
      res.push(dqs[i]);
    }}
    return res;
    }
}
//como usar
var todos_p_destaque_filhos_de_content = cssQuery('#content p.destaque');

Obs.1: Não quis mexer com o prototype do "document" porque uso isso dentro de uma lib minha e iria ficar melhor pra mim assim. Você pode adaptá-la e postar nos comentários se quiser.

Obs.2: Só irá funcionar com seletores NATIVOS do navegador em que estiver. Portanto se for usar um "div>p.classetal" no IE, provavelmente não irá funcionar.

Pequena explicação sobre o truque deste CSSQuery:

  1. Primeiro testo se o querySelectorAll existe no navegador atual (aquele primeiro if). Se existe, então uso ele.
  2. Se não existe, irei adicionar um "style" ao documento.
  3. O conteúdo deste style usa expressions - uma funcionalidade de CSS exclusiva do Internet Explorer que permite embutir scripts dentro das folhas de estilo. Você já deve conhecê-la caso já tenha usado meu velho Ultimate menu drop-down, onde uso expressions pra simular o :hover no IE.
  4. O que foi escrito dentro do style embutido (cssText) é a criação de uma regra onde o seletor é o parametro "sel" passado (o caminho do elemento). 
  5. Dentro da regra, eu pego o próprio elemento encontrato (this) e adiciono em uma variável __qsResult.
  6. Simples não? Genial.


(Pra quem quiser ver um exemplo do novo Mwords em funcionamento, olhem este site).

Até mais.

Gostou da dica acima? Então clica nos botões de compartilhamento abaixo e me ajude a dica a subir no Google.

2 comentários:

  1. Porque não o Sizzle??

    Essa forma apresentada não funciona com os seletores que não funcionarem no IE - de cada específica versão

    Como você disse, tb não funciona pra FF3.5, ainda que eu imagine que você já não dê mais suporte ao vovô.

    Sizzle minificado e gzipado via YUI fica com 5.3K

    ResponderExcluir
  2. Cara, nunca que vou colocar uma função que minificada fica 5.3k em minha lib hhehe. Só pra ter uma noção, minha lib toda está com 10k. Prefiro usar o velho getElementById. Mas valeu a dica do Sizzle, eu não conhecia.

    Sobre o FF3.5, o querySelector NATIVO não funciona. Esta função do ajaxian acima funciona.

    Sobre os seletores do IE: foi uma boa observação que você fez, vou colocar lá no post agora.

    VAleu

    ResponderExcluir

Resultado! Concursos