Existe uma maneira de impedir que 'isto' de mudar, quando eu embrulhar uma função?
-
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>
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.