jQuery primeiro filho de "this"

317

Eu estou tentando passar "this" de um período clicado para uma função jQuery que pode executar o jQuery no primeiro filho desse elemento clicado. Não consigo acertar ...

<p onclick="toggleSection($(this));"><span class="redClass"></span></p>

Javascript:

function toggleSection(element) {
  element.toggleClass("redClass");
}

Como faço para referenciar o: primeiro filho do elemento?

macca1
fonte
4
Se você estiver usando jQuery, por que não vincula manipuladores de eventos usando jQuery também?
Vivin Paliath
2
porque os manipuladores de eventos de ligação precisam ser inicializados em document.ready (), que adiciona um resultado de desempenho (este é um aplicativo para o IE6). Ou existe outra maneira?
macca1
Hum .. não tenho certeza. A ligação usando o jQuery é a maneira padrão (se você já estiver usando o jQuery). Que tipo de impacto no desempenho você está experimentando quando usa jQuery(document).ready(...)?
Vivin Paliath
É um aplicativo grande com mais de 7 desenvolvedores. Foi originalmente 4+ segundos antes de eu tentar limpá-lo um pouco. Então, eu prefiro evitar a adição de mais do que isso quando eu não tenho que :)
macca1

Respostas:

482

Se você deseja aplicar um seletor ao contexto fornecido por um conjunto jQuery existente, tente a função find () :

element.find(">:first-child").toggleClass("redClass");

Jørn Schou-Rode observou que você provavelmente só deseja encontrar o primeiro descendente direto do elemento de contexto, daí o seletor filho (>). Ele também aponta que você também pode usar a função children () , que é muito semelhante a find (), mas apenas pesquisa um nível profundo na hierarquia (que é tudo que você precisa ...):

element.children(":first").toggleClass("redClass");
Shog9
fonte
1
obrigado! funciona perfeitamente. Imagino que as outras maneiras listadas abaixo também funcionem.
macca1
6
Acredito que find()buscas em todos os descendentes e :first-childpodem corresponder a um elemento por pai. Portanto, é provável que essa consulta retorne vários elementos. Ou estou enganado?
Jørn Schou-Rode
19
Sei que essa é uma pergunta / resposta antiga, mas o uso do seletor ">" sem um pai nesse seletor é depreciado (por exemplo, ">: firstchild") a partir do jQuery 1.8. Sugiro, em vez disso, usar element.children(":first-child")ouelement.children().first();
Kevin B
3
@KevinB aparentemente eles decidiram não depreciar-lo depois de tudo
Alnitak
1
a melhor abordagem seria NÃO iterar em todos os itens e escolher o primeiro, conforme sugerido aqui. Isso seria ruim.
vsync
74

Use a childrenfunção com o :firstseletor para obter o primeiro filho único de element:

element.children(":first").toggleClass("redClass");
Jørn Schou-Rode
fonte
element.children () [0] .toggleClass ("redClass");
Zakos
5
@Zakos:TypeError: Object [object HTMLAnchorElement] has no method 'toggleClass'
Jørn Schou-Rode
51

Eu adicionei JSPerf teste para ver a diferença de velocidade para diferentes abordagens para obter o primeiro filho (total 1000 crianças)

dado, notif = $('#foo')

Maneiras jQuery:

  1. $(":first-child", notif) - 4.304 ops / s - mais rápido
  2. notif.children(":first") - 653 ops / s - 85% mais lento
  3. notif.children()[0] - 1.416 ops / s - 67% mais lento

Maneiras nativas:

  1. JavaScript nativo ' ele.firstChild- 4.934.323 ops / s (todas as abordagens acima são 100% mais lentas em comparação com firstChild)
  2. Ele DOM nativo do jQery: notif[0].firstChild- 4.913.658 ops / s

Portanto, as três primeiras abordagens do jQuery não são recomendadas, pelo menos para o primeiro filho (duvido que seja o caso de muitas outras também). Se você tiver um objeto jQuery e precisar obter o primeiro filho, obtenha o elemento DOM nativo do objeto jQuery, usando a referência de matriz [0] (recomendado) ou .get(0)use o ele.firstChild. Isso fornece os mesmos resultados idênticos aos do uso regular do JavaScript.

todos os testes são feitos no Chrome Canary build v15.0.854.0

manikanta
fonte
20
Na verdade, firstChildnão fornecerá os mesmos resultados que as children()consultas do jQuery ou do seletor. firstChildincluirá nós de texto que raramente são desejados. A contents()função do jQuery irá incluí-los, mas children()não o fará. Navegadores mais novos suportam o firstElementChildque fornecerá o primeiro elemento filho, mas o IE <9 não o suporta. Portanto, se você usar, firstChildprecisará localizar manualmente o primeiro filho do nó que não é de texto.
Max
1
$(":first-child", notif)deve ser $(":first", notif)para o comportamento esperado. O primeiro retornará todos os descendentes de elementos do primeiro filho.
Drazen Bjelovuk 6/03/2017
18
element.children().first();

Encontre todas as crianças e obtenha primeiro.

Bishal Paudel
fonte
1
De longe o método mais simples e mais eficiente que .children(':first').
Gras Double
3
Como é mais eficiente? Parece que ele pega todas as crianças e depois pega a primeira, em vez de pegar apenas a primeira.
Anthony McGrath
9

Você tentou

$(":first-child", element).toggleClass("redClass");

Eu acho que você deseja definir seu elemento como um contexto para sua pesquisa. Pode haver uma maneira melhor de fazer isso, que algum outro guru do jQuery entrará aqui e jogará fora em você :)

theIV
fonte
3
este irá falhar se elementtem netos
Alnitak
4

Acabei de escrever um plugin que usa, .firstElementChildse possível, e volta a iterar sobre cada nó individual, se necessário:

(function ($) {
    var useElementChild = ('firstElementChild' in document.createElement('div'));

    $.fn.firstChild = function () {
        return this.map(function() {
            if (useElementChild) {
                return this.firstElementChild;
            } else {
                var node = this.firstChild;
                while (node) {
                    if (node.type === 1) {
                        break;
                    }
                    node = node.nextSibling;
                }
                return node;
            }
        });
    };
})(jQuery);

Não é tão rápido quanto uma solução DOM pura, mas nos testes do jsperf no Chrome 24, foram duas ordens de magnitude mais rápidas do que qualquer outro método baseado no seletor do jQuery.

Alnitak
fonte
1
Eu gosto deste plug-in - mas existem 2 problemas: 1) O script do plug-in não pode ser incluído na cabeça porque document.bodyainda não foi inicializado; 2) O desempenho é muito melhor do que as alternativas se o número de nós filhos for muito alto. Para apenas algumas crianças (digamos menos de 10), o $('>:first-child',context)é um pouco mais rápido. Somente o número de filhos afeta o desempenho, não a profundidade.
Codefactor
@ codefactor bom ponto sobre document.body- eu vou olhar para isso.
Alnitak
4

você pode usar o DOM

$(this).children().first()
// is equivalent to
$(this.firstChild)
Yukulélé
fonte
1

use-o como esta primeira coisa, dê um nome de classe para marcar p como "myp"

em seguida, use o seguinte código

$(document).ready(function() {
    $(".myp").click(function() {
        $(this).children(":first").toggleClass("classname"); // this will access the span.
    })
})
vishal gupta
fonte
-3

Se você quer o primeiro filho imediato, precisa

    $(element).first();

Se você deseja um primeiro elemento específico no dom do seu elemento, use abaixo

    var spanElement = $(elementId).find(".redClass :first");
    $(spanElement).addClass("yourClassHere");

experimente: http://jsfiddle.net/vgGbc/2/

Amit Rathod
fonte
11
isso está errado - se elementé um nó DOM, então $(element).first()é equivalente $(element), e não seu primeiro filho.
Alnitak
1
Acordado, se o elemento é um nó DOM $ (elemento) .Em primeiro lugar () é de US $ equivalente (elemento), este problema causou-me com a ligação knockoutJS
DRGN