Existe uma maneira de impedir que 'isto' de mudar, quando eu embrulhar uma função?

StackOverflow https://stackoverflow.com/questions/400968

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu quero que todos os botões para executar uma ação antes e depois de seu evento onclick normal. Então eu vim com a idéia "brilhante" de loop através de todos os elementos e criar uma função wrapper.

Este parecia funcionar muito bem quando eu testei, mas quando eu integrá-lo em nosso aplicativo, ele se desfez. Eu segui-lo para o 'isto' valor foi alterado pelo meu wrapper. O código de exemplo ilustra este; antes de embrulhar os manipuladores de eventos, cada botão exibe o botão id quando você clica, mas depois de envolvê-lo o nome exibido é 'indefinido' neste exemplo, ou 'Form1' se você executá-lo de dentro de um formulário.

Alguém sabe seja uma maneira melhor de fazer a mesma coisa? Ou uma boa maneira de manter o inicialmente previsto 'isto' valores?

Como você pode imaginar, eu não quero modificar qualquer parte do código do manipulador de eventos existente nos botões de destino.

Agradecemos antecipadamente.

PS-O navegador de destino é IE6 &-se, funcionalidade crossbrowser não é necessário

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<script language="javascript" type="text/javascript">
    function btnWrap_onClick()
    {
        var btns = document.getElementsByTagName("button");
        for( var i = 0; i < btns.length; i++)
        {
            var btn = btns[i];

            // handle wrap button differerntly
            if( "btnWrap" == btn.id)
            {
                btn.disabled = true;
                continue; // skip this button
            }

            // wrap it
            var originalEventHandler = btn.onclick;
            btn.onclick = function()
            {
                alert("Starting event handler");
                originalEventHandler();
                alert("Finished event handler");
            }
        }

        alert("Buttons wrapped successfully");
    }
</script>
<body>
    <p>
    <button id="TestButton1" onclick="alert(this.id);">TestButton1</button>
    <button id="TestButton2" onclick="alert(this.id);">TestButton2</button>
    </p>
    <button id="btnWrap" onclick="btnWrap_onClick();">Wrap Event Handlers</button>
</body>
</html>
Foi útil?

Solução

Como Paul Dixon disse, você poderia usar chamada mas eu sugiro que você use se candidatar .

No entanto, a razão pela qual eu estou respondendo é que eu encontrei um bug perturbar:. Você está substituindo realmente todos os seus manipuladores de eventos com o manipulador de eventos do último botão eu não acho que isso era o que você pretendeu, foi? (Dica: Você está substituindo o valor para originalEventHandler em cada iteração)

No código abaixo você encontrar uma solução cross-browser de trabalho:

function btnWrap_onClick()
{
    var btns = document.getElementsByTagName("button");
    for( var i = 0; i < btns.length; i++)
    {
        var btn = btns[i];

        // handle wrap button differerntly
        if( "btnWrap" == btn.id)
        {
            btn.disabled = true;
            continue; // skip this button
        }

        // wrap it

        var newOnClick = function()
        {
            alert("Starting event handler");
            var src=arguments.callee;
            src.original.apply(src.source,arguments);
            alert("Finished event handler");
        }
        newOnClick.original = btn.onclick; // Save original onClick
        newOnClick.source = btn; // Save source for "this"
        btn.onclick = newOnClick; //Assign new handler
    }
alert("Buttons wrapped successfully");
}

Primeiro eu criar uma nova função anônima e loja que na variável newOnClick . Uma vez que uma função é um objeto que pode criar propriedades no objeto função como qualquer outro objeto. Eu uso isso para criar a propriedade ORIGINAL , que é o original onclick manipulador, e source , que é o elemento de origem que será o este quando o manipulador original é chamada.

Dentro da função anônima que eu preciso para obter uma referência para a função de ser capaz de obter o valor das propriedades ORIGINAL e source . Desde que a função anônima não tem um nome que eu uso o uso arguments.callee (que tem sido apoiado desde MSIE5.5) para obter essa referência e armazená-lo em src variável.

Então eu uso o método se candidatar para executar o manipulador onclick originais. se candidatar tem dois parâmetros: o primeiro vai ser o valor de este , ea segunda é uma matriz de argumentos. este tem que ser o elemento onde o manipulador onclick original foi anexado ao e esse valor foi salvo no source . argumentos é uma propriedade interna de todas as funções e mantenha todos os argumentos a função foi chamado com (note que a função anônima não tem nenhum parâmetro especificado, mas se ele é chamado com alguns parâmetros de qualquer maneira, eles será encontrada no argumentos propriedade).

O uso razão de eu se candidatar é que eu posso encaminhar todos os argumentos que a função anônima foi chamado com, e isso faz com que esta função transparente e cross-browser. (Microsoft colocar o evento em window.event mas os outros navegadores suprimentos de TI no primeiro parâmetro da chamada manipulador)

Outras dicas

Você pode usar o método href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Function/call" rel="nofollow noreferrer"> chamada originalEventHandler.call(btn);

Como alternativa, uma biblioteca como protótipo pode ajudar - seu método ligam permite que você construa uma nova função vinculado a um objeto específico, para que você teria declarado originalEventHandler como var originalEventHandler = btn.onclick.bind(btn);

Finalmente, para uma boa backgrounder sobre questões de ligação, ver também sair de situações obrigatório em JavaScript

Seu problema é a maneira como fechamentos de trabalhar em JavaScript. Honestamente, eu recomendo usar um quadro. Qualquer um deles deve fazer evento de manipulação muito melhor do que fazê-lo manualmente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top