JavaScript:添加onClick处理程序而不覆盖现有处理程序

时间:2009-05-21 09:01:47

标签: javascript jquery 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 仅在调用处理程序时进行评估(它包含 last 链接的值作为此点)。

7 个答案:

答案 0 :(得分:19)

不要直接分配给事件处理程序:使用订阅模型 addEventListener / attachEvent (它也有删除对!)。

好的介绍here

答案 1 :(得分:16)

您需要创建一个闭包以保留每个链接的原始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>

请注意,如果原始onclick处理程序返回true,则此实现仅执行新的onclick处理。如果这是你想要的,那就没关系了,但请记住,如果你想要执行新的onclick处理,即使原始处理程序返回false,你也必须稍微修改一下代码。

有关comp.lang.javascript FAQDouglas Crockford的关闭的详情。

答案 2 :(得分:4)

addEventListener(支持DOM的浏览器)或attachEvent(IE)周围使用包装。

请注意,如果您希望在不覆盖旧值的情况下将值存储在变量中,则可以使用closures

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);

Aspect Oriented Programming中,这被称为“advice”。

答案 3 :(得分:0)

使用JQuery,以下代码可以工作:

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

这需要使用额外的库,但避免了addEventListener / attachEvent存在的一些问题(就像后者对this references的问题)。

只有一个陷阱:如果使用“普通”JavaScript分配原始 onClick 处理程序,那么该行

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

将始终解析为<​​strong> true ,即使原始处理程序通过返回false取消了该事件。要解决这个问题,原始处理程序也必须使用JQuery。

答案 4 :(得分: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);
}

答案 5 :(得分:0)

我以简单的方式遇到重载问题 - 这个页面是一个很好的资源 http://www.quirksmode.org/js/events_advanced.html

答案 6 :(得分:0)

如何设置oldClick = links[i].onclick or an empty function。像这样

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

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

或者您可以像其他人推荐的那样使用attachEventaddEventListener

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]);