Posso chamar jquery click () para seguir um link <a> se ainda não tiver vinculado um manipulador de eventos a ele com bind ou clique?

175

Eu tenho um timer no meu JavaScript que precisa emular o clique em um link para ir para outra página depois que o tempo passa. Para fazer isso, estou usando a click()função jQuery . Eu usei $().trigger()e window.locationtambém, e posso fazê-lo funcionar como planejado com todos os três.

Eu observei algum comportamento estranho click()e estou tentando entender o que acontece e por quê.

Estou usando o Firefox para tudo o que descrevo nesta pergunta, mas também estou interessado no que outros navegadores farão com isso.

Se eu não usei $('a').bind('click',fn)ou $('a').click(fn)defini um manipulador de eventos, a chamada $('a').click()parece não fazer nada. Ele não chama o manipulador padrão do navegador para este evento, pois o navegador não carrega a nova página.

No entanto, se eu definir um manipulador de eventos primeiro, ele funcionará conforme o esperado, mesmo que o manipulador de eventos não faça nada.

$('a').click(function(){return true;}).click();

Isso carrega a nova página como se eu tivesse clicado no a.

Portanto, minha pergunta é dupla: esse comportamento é estranho porque estou fazendo algo errado em algum lugar? e por que chamar não click()faz nada com o comportamento padrão se eu não criei meu próprio manipulador?

EDITAR:

Como Hoffman determinou quando tentou duplicar meus resultados, o resultado que descrevi acima não acontece realmente. Não sei ao certo o que causou os eventos que observei ontem, mas hoje estou certo de que não foi o que descrevi na pergunta.

Portanto, a resposta é que você não pode "falsificar" cliques no navegador e tudo o que o jQuery faz é chamar seu manipulador de eventos. Você ainda pode usar window.locationpara alterar a página, e isso funciona bem para mim.

Mnebuerquo
fonte
2
Pode ser uma solução: stackoverflow.com/questions/31687759/...
Sukrit Chhabra

Respostas:

90

Interessante, essa é provavelmente uma "solicitação de recurso" (ou seja, bug) para o jQuery. O evento click do jQuery aciona apenas a ação click (chamada evento onClick no DOM) no elemento se você vincular um evento jQuery ao elemento. Você deve ir para as listas de discussão do jQuery ( http://forum.jquery.com/ ) e relatar isso. Esse pode ser o comportamento desejado, mas acho que não.

EDITAR:

Fiz alguns testes e o que você disse está errado, mesmo que você vincule uma função a uma tag 'a', ela ainda não o levará ao site especificado pelo atributo href. Tente o seguinte código:

<html>
<head>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
 <script>
  $(document).ready(function() {
   /* Try to dis-comment this:
   $('#a').click(function () {
    alert('jQuery.click()');
    return true;
   });
   */
  });
  function button_onClick() {
   $('#a').click();
  }
  function a_onClick() {
   alert('a_onClick');
  }
 </script>

</head>
<body>
 <input type="button" onclick="button_onClick()">
 <br>
 <a id='a' href='http://www.google.com' onClick="a_onClick()"> aaa </a>

</body>
</html> 

Ele nunca acessa o google.com, a menos que você clique diretamente no link (com ou sem o código comentado). Observe também que, mesmo que você vincule o evento click ao link, ele ainda não ficará roxo quando você clicar no botão. Só fica roxo se você clicar no link diretamente.

Eu fiz algumas pesquisas e parece que o .click não deve funcionar com as tags 'a' porque o navegador não suporta "cliques falsos" com javascript. Quero dizer, você não pode "clicar" em um elemento com javascript. Com as tags 'a', você pode acionar o evento onClick, mas o link não muda de cor (para a cor do link visitado, o padrão é roxo na maioria dos navegadores). Portanto, não faria sentido fazer o evento $ (). Click funcionar com as tags 'a', pois o ato de ir para o atributo href não faz parte do evento onClick, mas é codificado no navegador.

Hoffmann
fonte
7
Eu tentei o seu código e ele faz exatamente como você disse, mas meu código é como eu descrevi acima. Vou fazer mais algumas experiências e ver se consigo reunir um exemplo simples dos meus resultados que você pode tentar.
Mnebuerquo
1
Está bem. Deve ter sido algo que eu fiz de errado. Eu tinha certeza absoluta de que, no momento em que postei minha pergunta, estava funcionando, mas desde que tentei o seu exemplo, o meu não funciona mais. Voltarei a usar window.location para alterar a página e não tentar fingir o clique.
Mnebuerquo
De fato, o click () não se destina a criar cliques falsos, mas às vezes podemos usá-lo para clicar em botões ou formulários com injeções de javascript ou apenas para maior comodidade ao criar uma tecla de atalho temporária sobre as funções javascript existentes.
Aero Wang
241

Outra opção é, obviamente, usar apenas o javascript de baunilha:

document.getElementById("a_link").click()
Peter
fonte
1
Isso não funciona no Safari e, de acordo com as especificações HTML, apenas as entradas precisam implementar isso.
Jeremy Kauffman
4
Dang! Isso funciona! Mas devo dizer que não é bastante javascript "vanilla", já que é através de um elemento jQuery, por isso é uma espécie de-baunilha JavaScript jQuery .... Ele funciona no Firefox 24 e IE 10.
bgmCoder
@ BMG, ok, mas o click () não está em um elemento jquery. Você pode substituí-lo por getElementById (".."). Click ()
Peter
uau ferido cheio, funciona como eu esperava. +1 dado :). Para outros usuários, você também pode usar como: var lnk = document.getElementById ("a_link"); if (lnk == null) {// faça alguns ....} else {lnk.click (); }
Iqbal
Testado em vários navegadores, o IE10 e o Jquery 1.6.4 não conseguem lidar com isso.
Hannes Schneidermayer
65

Se você olhar para o código da $.clickfunção, aposto que há uma declaração condicional que verifica se o elemento possui ouvintes registrados para o clickevento antes de prosseguir. Por que não obter o hrefatributo no link e alterar manualmente o local da página?

 window.location.href = $('a').attr('href');

EDIT: Aqui está o motivo pelo qual ele não clica na triggerfonte jQuery da versão 1.3.2:

 // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
    if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
        event.result = false;

    // Trigger the native events (except for clicks on links)
    if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
        this.triggered = true;
        try {
            elem[ type ]();
        // prevent IE from throwing an error for some hidden elements
        } catch (e) {}
    }

Depois de chamar manipuladores (se houver), o jQuery dispara um evento no objeto. No entanto, ele chama apenas manipuladores nativos para eventos de clique se o elemento não for um link. Eu acho que isso foi feito propositadamente por algum motivo. Isso deve ser verdade, independentemente de um manipulador de eventos ser definido ou não, portanto, não sei por que, no seu caso, anexar um manipulador de eventos fez com que o onClickmanipulador nativo fosse chamado. Você terá que fazer o que eu fiz e percorrer a execução para ver para onde está sendo chamada.

Ryan Lynch
fonte
Certamente posso usar window.location e o href, como mencionei na pergunta. Estou tentando entender o que acontece no jquery click () e o que causa os resultados que observei.
Mnebuerquo
Eu editei minha resposta para mostrar onde na fonte do jQuery ele lida com chamadas $ .click () nos links.
21919 Ryan Lynch
2
window.location funciona, mas não não publica o Referenciador HTTP e quebra o botão Voltar.
usar o seguinte código
5

Os manipuladores de cliques nas tags âncora são um caso especial no jQuery.

Eu acho que você pode estar ficando confuso entre o evento onclick da âncora (conhecido pelo navegador) e o evento click do objeto jQuery que envolve a noção de DOM da tag anchor.

Você pode baixar a fonte do jQuery 1.3.2 aqui .

As seções relevantes da fonte são as linhas 2643-2645 (eu dividi isso em várias linhas para facilitar a compreensão):

// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
if (
     (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && 
       elem["on"+type] && 
       elem["on"+type].apply( elem, data ) === false
   )
     event.result = false;
marechally
fonte
5

JS / jQuery não suporta o comportamento padrão dos links "clicados" programaticamente.

O que você pode fazer é criar um formulário e enviá-lo. Dessa forma, você não precisa usar window.locationou window.open, que geralmente são bloqueados como pop-ups indesejados pelos navegadores.

Esse script possui 2 métodos diferentes: um que tenta abrir 3 novas guias / janelas (abre apenas 1 no IE e Chrome, mais informações abaixo) e outro que aciona um evento personalizado ao clicar no link.

Aqui está como:

HTML

<html>
<head>
    <script src="jquery-1.9.1.min.js" type="text/javascript"></script>
    <script src="script.js" type="text/javascript"></script>
</head>
<body>
    <button id="testbtn">Test</button><br><br>

    <a href="https://google.nl">GOOGLE</a><br>
    <a href="http://en.wikipedia.org/wiki/Main_Page">WIKI</a><br>
    <a href="https://stackoverflow.com/">SO</a>
</body>
</html>

jQuery (script.js)

$(function()
{ 
    // Try to open all 3 links by pressing the button
    // - Firefox opens all 3 links
    // - Chrome only opens 1 of them without popup warning
    // - IE only opens 1 of them WITH popup warning
    $("#testbtn").on("click", function()
    {
        $("a").each(function()
        {
            var form = $("<form></form>");
            form.attr(
            {
                id     : "formform",
                action : $(this).attr("href"),
                method : "GET",
                // Open in new window/tab
                target : "_blank"
            });

            $("body").append(form);
            $("#formform").submit();
            $("#formform").remove();
        });
    });

    // Or click the link and fire a custom event 
    // (open your own window without following the link itself)
    $("a").on("click", function()
    {
        var form = $("<form></form>");
        form.attr(
        {
            id     : "formform",
            // The location given in the link itself
            action : $(this).attr("href"), 
            method : "GET",
            // Open in new window/tab
            target : "_blank"              
        });

        $("body").append(form);
        $("#formform").submit();
        $("#formform").remove();

        // Prevent the link from opening normally
        return false;
    });

});

O que ele faz é para cada elemento do link:

  1. Crie um formulário
  2. Atribua atributos
  3. Anexe-o ao DOM para que possa ser enviado
  4. Envie
  5. Remova o formulário do DOM, removendo todos os vestígios * Insira risada maligna *

Agora você tem um novo carregamento de guia / janela "https://google.nl"(ou qualquer URL que desejar, basta substituí-lo). Infelizmente, ao tentar abrir mais de uma janela dessa maneira, você recebe uma Popup blockedbarra de mensagens ao tentar abrir a segunda (a primeira ainda está aberta).


Mais informações sobre como cheguei a esse método são encontradas aqui:

Abrir nova janela / guia sem usar window.openouwindow.location.href

Richard de Wit
fonte
3

Acione um elemento Hyperlink que esteja dentro do elemento que você deseja conectar ao jquery .click ()

<div class="TopicControl">
    <div class="articleImage">
       <a href=""><img src="" alt=""></a>
    </div>
</div>

No seu script, você conecta ao contêiner principal no qual deseja o evento click. Então você usa a metodologia jquery padrão para encontrar o elemento (tipo, classe, ID) e acionar o clique. O que acontece é que o jquery entra em uma função recursiva para acionar o clique e você interrompe a função recursiva ao pegar a função de evento 'e' e stopPropagation () e retornar false porque você não deseja que o jquery faça mais nada além de acionar o link.

$('.TopicControl').click(function (event) {
         $(this).find('a').click();
        event.stopPropagation();
        return false;
     });

A solução alternativa é envolver os contêineres no elemento e colocá-los como contêineres dentro, em vez de s. Defina os vãos para exibir o bloco em conformidade com os padrões w3c.

Paul Styles
fonte
3

Você pode usar o jQuery para selecionar o objeto jQuery para esse elemento. Em seguida, obtenha o elemento DOM subjacente e chame seu click()método.

por id

$("#my-link").each(function (index) { $(this).get(0).click() });

ou use o jQuery para clicar em vários links por classe CSS

$(".my-link-class").each(function (index) { $(this).get(0).click() });
10GritSpaper
fonte
2

Não faz nada porque nenhum evento foi vinculado ao evento. Se bem me lembro, o jQuery mantém sua própria lista de manipuladores de eventos que estão vinculados a NodeLists para desempenho e outros fins.

JasonWyatt
fonte
2

Se você precisar desse recurso para um caso ou muito poucos casses. (o aplicativo inteiro não está exigindo esse recurso) Prefiro deixar o jQuery como está (por vários motivos, incluindo a possibilidade de atualizar para versões mais recentes, CDN etc.) e ter a seguinte solução alternativa:

// For modren Browsers
$(ele).trigger("click");

// Relaying on Paul Irish's conditional class names http://bit.ly/HWIpAp (via HTML5 Boilerplate http://bit.ly/HUzi3I) where each IE version gets a class of its Version
$("html.ie7").length && (function(){
    var eleOnClickattr = $(ele).attr("onclick") 
    eval(eleOnClickattr);
  })()
adardesign
fonte
1

Para abrir o hiperlink na mesma guia, use:

$(document).on('click', "a.classname", function() {
    var form = $("<form></form>");
    form.attr(
    {
        id     : "formid",
        action : $(this).attr("href"),
        method : "GET",
    });

    $("body").append(form);
    $("#formid").submit();
    $("#formid").remove();
    return false;
});
DHARMENDRA SINGH
fonte