使用JQuery在按钮上添加onclick操作

w7t8yxp5  于 2023-11-17  发布在  jQuery
关注(0)|答案(7)|浏览(163)

我有一个按钮,它已经有一个onclick事件和一个分配的函数。我希望在它前面添加另一个函数调用。我可以想象它应该可以摆弄onclick属性(attr),但我不认为这是最佳实践。
你认为在现有的onclick-event上预挂一个函数调用的最佳实践是什么?

goqiplq2

goqiplq21#

如果你不害怕弄乱jQuery的内脏:

// "prepend event" functionality as a jQuery plugin
$.fn.extend({
  prependEvent: function (event, handler) {
    return this.each(function () {
      var events = $(this).data("events"), 
          currentHandler;

      if (events && events[event].length > 0) {
        currentHandler = events[event][0].handler;
        events[event][0].handler = function () {
          handler.apply(this, arguments);
          currentHandler.apply(this, arguments);
        }      
      }
    });
  }
});

$("#someElement").prependEvent("click", function () {
    whatever();
});​

字符串
现场观看:http://jsfiddle.net/Tomalak/JtY7H/1/
请注意,必须已经有一个currentHandler,否则该函数将不做任何事情。

  • 免责声明:* 我认为这是一个黑客。它取决于jQuery内部,可能会在下一个版本的库中发生变化。它现在可以工作(我测试了jQuery 1.7.2),但如果它与jQuery的未来版本发生冲突,请不要感到惊讶。*
bgtovc5b

bgtovc5b2#

我在这里写了一个简短的example

​$("button").click(function() { // this is already existing
    if ($("span").length) {
        alert("ok");
    }
});

var clicks = $("button").data("events").click.slice();
$("button")
    .unbind("click")
    .click(function() { // this is the new one which should be prepended
        $("body").append($("<span>"));
    });
$.each(clicks, function(i, v) {
    $("button").click(v);
});

字符串

k7fdbhmy

k7fdbhmy3#

我不认为有一种方法可以在现有的onclick事件上预挂一个函数调用,但是你可以尝试这样做:

$('#foo').unbind('click');
$('#foo').click(function() { 
   // do new function call..
   // call original function again...
});

字符串
希望能帮上忙。

elcex8rz

elcex8rz4#

你可以在单个事件上添加函数,但我尽量避免在onclick事件上添加两个函数。
1.在现有函数中添加新代码。
2.从现有函数添加对新函数的调用。

hgtggwj0

hgtggwj05#

这似乎在1.9.1到3.1.4中都可以工作。有关1.9.1之前的版本,请参阅Tomalak's awesome answer

$(function() {
  $("input" ).mousedown( function() {
    console.log( "mousedown" );
  });

  $("input" ).click( function() {
    console.log( "click" );
  });
    
  $.fn.extend({exposeListeners: 
      function (fn) {
        return $._data( this[0], "events") || {};
      },
    prependListener: function (types, fn) {
      var elems = this;
      $(elems).each(function() {
        var elem = this;
        var $elem = $(elem)
        $elem.on(types, fn);

        var events = $._data( $elem[0], "events")[types];

        if (events.length > 1) { // its the only event, no reason to shift
            events.unshift(events.pop());  // put last as first
        }
    
        return this;
      });
    }
  })
  
  $("#prep").click(function () {
    console.log($("input").exposeListeners());
    $("input:not(:last)").prependListener("click", function () {
      console.log('click, prepended');
    })
    $("a").prependListener("click", function () {
      console.log('click event created');
    })
    console.log($("body").exposeListeners());
  })
});

个字符
这是一个粗略的版本

$(function() {
  $.fn.extend({prependListener: function (types, fn) {
      var elems = this;
      $(elems).each(function() {
        var elem = this;
        var $elem = $(elem)
        $elem.on(types, fn);

        var events = $._data( $elem[0], "events")[types];

        if (events.length > 1) {
          events.unshift(events[events.length-1]);
          events.pop();
        }
    
        return this;
      });
    }
  })
})

wd2eg0qa

wd2eg0qa6#

使用JQuery 3.3.1测试(但可能适用于1.9.1及更高版本)。1.9.1之前的版本请参阅Tomalak's answer
我公司的一个项目有一个问题(现已修复),我注意到:

  • 另一个global-script已经在处理提交,我们称之为global-handler,
  • global-handler阻止了默认行为,
  • global-handler最终以编程方式导致重定向。

删除和/或更改所述全局处理程序在当时不是一个选项。
jQuery按照注册的顺序调用侦听器/处理程序,这意味着:

  • 因为总是需要全局处理程序的逻辑,
  • 但我自己的逻辑只在少数几种形式上需要,
  • 我需要我自己的处理程序的逻辑来充当“中间件”,换句话说:
  • 我需要一个方法来预先准备我自己的接头人
  • 然后,只有当我自己的处理程序的验证逻辑失败时,才阻止全局处理程序的逻辑被调用。
  • 否则,总是调用全局处理程序的逻辑。

解决方案

注意,我使用的是Type-script,但如果需要,您可以强制转换为JavaScript(只需删除类型和declare global部分?)。

首先,在某个地方定义,可能是plugins.ts文件,帮助程序和/或JQuery插件,比如:

import $ from 'jquery';

export type Middleware = (next: () => void) => void;

declare global {
  interface JQuery<TElement = HTMLElement> {
    /**
     * Prepends given `middleware` to be called on enter-key and click events.
     *
     * Also, passes a trigger to "default click operation" as first argument
     * (the `next()` callback).
     *
     * WARNING: registering multiple {@link Middleware} is NOT supported yet
     * (if all target same element).
     */
    clickMiddleware(middleware: Middleware): JQuery;

    /**
     * Same as {@link JQuery.trigger} for click, but cross-platform.
     *
     * For example, JQuery intentionally does nothing for Anchor-tags
     * (which is their way to be cross-platform).
     */
    clickCompat(): JQuery;

    /**
     * Same as {@link JQuery.on}, but prepends handler.
     *
     * Additionally, may replace inline-handlers with JQuery handler
     * (because they get called before JQuery's handler).
     */
    prependEvent<TString extends string>(
      events: TString,
      handler: false
        | JQuery.TypeEventHandler<TElement, undefined, TElement, TElement, TString>
    ): this;
  }
}

export function register() {
  (<any>$.fn).clickMiddleware = function (middleware: Middleware) {
    return $(this).prependEvent('keypress click', function (event: any) {
      // May already be past middleware.
      const $element = $(this);
      if ($element.prop('isCallingDefault')) {
        $element.prop('isCallingDefault', false);
        return true;
      }

      // Executes middleware (but only for enter-key and click events).
      const logicalKey = event.key || event.which || event.keyCode || 0;
      if (logicalKey === 13 || event.type === 'click') {
        if (event.stopImmediatePropagation) event.stopImmediatePropagation();
        if (event.stopPropagation) event.stopPropagation();
        event.preventDefault();

        middleware.call(this, function () {
          $element.prop('isCallingDefault', true);
          $element.clickCompat();
        });
        return false;
      }

      return true;
    });
  };

  (<any>$.fn).clickCompat = function () {
    $(this).each(function (index, element: HTMLElement) {
      if ((<any>document).dispatchEvent) {
        let event = null;
        try {
          event = new MouseEvent('click', {
            'view': window,
            'bubbles': true,
            'cancelable': false
          });
        } catch {
          event = document.createEvent('MouseEvents');
          // noinspection JSDeprecatedSymbols
          event.initMouseEvent('click', true, true,
            window, 0, 0, 0, 0, 0,
            false, false, false, false,
            0, null);
        }
        element.dispatchEvent(event);
      } else if ((<any>document).fireEvent) {
        element.click();
      }
    });
  };

  (<any>$.fn).prependEvent = function (eventList: string, handler: any) {
    // Using "container" param instead of "var container;".
    return $(this).each(function () {
      const $element = $(this);
      for (let event of eventList.split(' ')) {
        // Replaces inline-handlers (if possible).
        const attributeName = 'on' + event;
        const oldHandler = this[attributeName];
        if (oldHandler) {
          $element.attr(attributeName, null);
          internalPrependEvent($element, event, function () {
            oldHandler.apply(this, arguments);
          });
        }
        // Actual prepend.
        internalPrependEvent($element, event, handler);
      }
    });
  };
}

/**
 * NOTE: is already called form inside `$selection.each(...)`,
 * hence `$element.get(0)` is enough (no need to handle multiple elements).
 */
function internalPrependEvent(
  $element: JQuery<any>, eventName: string, handler: any
) {
  // Append new-listener.
  $element.on(eventName, handler);
  // Move above added new-listener to first in list.
  const container = (<any>$)._data($element.get(0), 'events')[eventName];
  container.unshift(container.pop());
}

字符串

用法

最后,在需要时导入并使用上述内容。
例如,OP可以像这样使用它:

require('./plugins').register();

$(function () {
    $('my-selector').prependEvent('click', function (event) {
        // Do something here...
    });
});


但我用它是这样的:

require('./plugins').register();

$(function () {
    $('my-selector').clickMiddleware(function (next) {
        var valid = ... my logic here ...;
        if (valid) {
            next();
        }
    });
});

注意,我的网站从CDN获取JQuery,我在我的web-pack配置中有这样的内容:

externals: {
   jquery: 'jQuery',
}

uqzxnwby

uqzxnwby7#

如果你像这样绑定事件

$(elem).on('click', functionName);

字符串
你可以这样修改它:

$(elem).on('click', function(){

 anotherFunctionNameOrWhateverYouWant();

 functionName();
});

相关问题