2009-05-21 36 views
15

クリックしたときにいくつかの追加作業を行うように、ページ上のすべてのリンクを修正しようとしています。JavaScript:既存のものを上書きせずにonClickハンドラを追加する

function adaptLinks() 
{ 
    var links = document.getElementsByTagName('a'); 
    for(i = 0; i != links.length; i++) 
    { 
     links[i].onclick = function (e) 
     { 
      <do some work> 
      return true; 
     } 
    } 
} 

しかし、リンクの一部は、すでに保存されるべきのonClickハンドラを持っている:

些細なアプローチは、このようなものかもしれません。私は、次のことを試してみました:

function adaptLinks() 
{ 
    var links = document.getElementsByTagName('a'); 
    for(i = 0; i != links.length; i++) 
    { 
     var oldOnClick = links[i].onclick; 
     links[i].onclick = function (e) 
     { 
      if(oldOnClick != null && !oldOnClick()) 
      { 
       return false; 
      } 
      <do some work> 
      return true; 
     } 
    } 
} 

しかし、ハンドラが(それはこのポイントとして最後リンクの値を含む)が呼び出されたときにoldOnClickのみが評価されるため、これは動作しません。

+0

ましたここでは、jQueryを使用して解決します。私は現在、いくつかの他のタスクも緩和しているように見ています。 – rluba

答えて

16

あなたは、各リンクの元onclick価値を維持するためにクロージャを作成する必要があります。元のハンドラがfalseを返す場合でも、新しいonclick処理を実行したい場合は、コードを少し修正する必要があることに留意してください。

comp.lang.javascript FAQおよびDouglas Crockfordでの閉鎖に関する詳細。

+0

+1クロージャのヒント。私の例は、元のハンドラがキャンセルしなかった場合にのみ実行するように特別に設計されているので、あなたの例はうまく収まります。 – rluba

18

直接イベントハンドラに割り当てないでください:サブスクライブ・モデルを使用しにaddEventListener/attachEventを代わりに(もペアを削除しています!)。

良い紹介here

+1

+1クワルクモードページ。 – outis

+0

または、もっと簡単に同じことができるようにするjavascriptライブラリ(/ meがjQueryに投票)を使用することができます。しかし、あなたはまだquirksmodeページで理論を理解しなければなりません。これは、JavaScript開発者のためにかなり魂を豊かにしています。 – jrharshath

+1

「緩和」は相対的です。私は5行の方法でこのものをラップすることができますか、私はマルチKライブラリをダウンロードすることができます。ライブラリは持っているのが良いですが、実際に何かを実際に行う方法を犠牲にすることはありません。私は反jqueryを投票しないだろう、私はちょうど膝の上に熱心ではない。 – annakata

4

addEventListener(DOMをサポートするブラウザ)またはattachEvent(IE)のラッパーを使用してください。

古い値を上書きせずに変数に値を保存する場合は、closuresを使用できます。 Aspect Oriented Programming

function chain(oldFunc, newFunc) { 
    if (oldFunc) { 
    return function() { 
     oldFunc.call(this, arguments); 
     newFunc.call(this, arguments); 
    } 
    } else { 
    return newFunc; 
    } 
} 

obj.method = chain(obj.method, newMethod); 

、これは "advice" として知られています。

0

設定方法oldClick = links[i].onclick or an empty function他の人が

function addEvent(obj, type, fn) { 
     if (obj.addEventListener) 
       obj.addEventListener(type, fn, false); 
     else if (obj.attachEvent) 
       obj.attachEvent('on' + type, function() { return fn.apply(obj, [window.event]);}); 
} 

をお勧めしますので、

addEvent(links[i], 'click', [your function here]); 
+0

ハンドラーが呼び出されたときにoldOnClickが評価され、ハンドラーが書き込まれたときには評価されないという問題は解決されません。 Plus:古いonclickハンドラがfalseを返す場合(リンクが動作しなくなる)、falseを返すことはできません。 – rluba

+0

ああ、私は問題をよりよく理解しています。 oldOnClickがfalseを返した場合、falseを返すことはできませんか? –

0

のjQueryを使用してのように使用してきたように

var oldOnClick = links[i].onclick || function() { return true; }; 

links[i].onclick = function (e) 
    { 
     if (!oldOnClick()) 
      return false; 
     //<do some work> 
     return true; 
    } 

それともattachEventを使用することができますし、addEventListenerので、同じように、次のコードは動作します:

function adaptLinks(table, sortableTable) 
{ 
    $('a[href]').click(function (e) 
    { 
     if(!e.isDefaultPrevented()) 
     { 
      <do some work> 
     } 
    }); 
} 

追加のライブラリを使用する必要がありますが、addEventListener/attachEventに存在する問題(this referencesの後者の問題のような)は避けてください。

ただ一つ落とし穴があります:元のonClickハンドラは「通常の」JavaScriptを使用して割り当てられている場合、

... 
if(!e.isDefaultPrevented()) 
... 

ラインは常にに解決され、場合であっても、元のハンドラがキャンセルfalseを返すことによってイベントを返します。これを修正するには、元のハンドラもJQueryを使用する必要があります。この実装は唯一のオリジナルのonclickハンドラがtrueを返した場合、新規のonclickの取り扱いを行うこと

<a href="#" onclick="alert('hi');return false;">Hi</a> 
<a href="#" onclick="alert('there');return true;">There</a> 
<script type="text/javascript"> 
function adaptLinks() { 
    var links = document.getElementsByTagName('a'); 
    for (i = 0; i != links.length; i++) { 
     links[i].onclick = (function() { 
      var origOnClick = links[i].onclick; 
      return function (e) { 
       if (origOnClick != null && !origOnClick()) { 
        return false; 
       } 
       // do new onclick handling only if 
       // original onclick returns true 
       alert('some work'); 
       return true; 
      } 
     })(); 
    } 
} 
adaptLinks(); 
</script> 

注:

0

この関数は、(イベントリスナーが近づいて)使用可能である必要があります。

function addEventListener(element, eventType, eventHandler, useCapture) { 
    if (element.addEventListener) { 
     element.addEventListener(eventType, eventHandler, useCapture); 
     return true; 
    } else if (element.attachEvent) { 
     return element.attachEvent('on' + eventType, eventHandler); 
    } 
    element['on' + eventType] = eventHandler; 
} 

か、この機能を追加するいくつかのより多くのコード(あなたは多くの要素に同じイベントリスナーを追加する必要がある場合)を保存することができます

function addClickListener(element) { 
    addEventListener(element, 'click', clickHandler, false); 
} 
関連する問題