【问题标题】:Automatically pass $event with ng-click?使用 ng-click 自动传递 $event?
【发布时间】:2025-12-30 12:55:16
【问题描述】:

我知道如果我像这样传入$event 对象,我可以从ng-click 访问点击事件:

<button ng-click="myFunction($event)">Give me the $event</button>

<script>
  function myFunction (event) {
    typeof event !== "undefined" // true
  }
</script>

每次都必须明确传递$event 有点烦人。是否可以将ng-click 设置为默认将其传递给函数?

【问题讨论】:

  • 我知道代码只是为了演示,但undefined 应该是"undefined",否则表达式将始终为 false,因为typeof 返回一个字符串。
  • 我想知道你为什么需要$event
  • @zeroflagL 事件对象通常用于停止冒泡/传播。
  • @Stewie myFunction 是控制器的一部分。控制器不应该关心 UI。此外,一个简单的按钮没有默认操作。无论如何,角度确实会阻止许多默认操作。因此,当然,尽管您是对的,但很难想象一个好的用例。
  • @zeroflagL 我有一个指令contextMenu,它为范围(打开、关闭、切换)提供了几个函数,这些函数以特定contextMenu 的名称调用,例如ng-click="account_menu.toggle()"。菜单本身位于不同的元素中,例如&lt;div context-menu="account_menu"&gt;&lt;/div&gt;"。为了将菜单正确定位在名为toggle() 的触发元素正下方的页面上,我想访问ng-click$event.target 元素,以便获得它的坐标。如果有更简单的方法,请告诉我:)

标签: javascript angularjs angularjs-directive dom-events angularjs-ng-click


【解决方案1】:

看看ng-click指令源:

...
compile: function($element, attr) {
  var fn = $parse(attr[directiveName]);
  return function(scope, element, attr) {
    element.on(lowercase(name), function(event) {
      scope.$apply(function() {
        fn(scope, {$event:event});
      });
    });
  };
}

It shows event 对象如何传递ng-click 表达式,使用$event 作为参数的名称。这是由 $parse 服务完成的,它不允许参数渗入目标范围,这意味着答案是否定的,您无法访问$event 对象除了通过回调参数之外的任何其他方式。

【讨论】:

    【解决方案2】:

    ng-click 中添加$event,例如:

    <button type="button" ng-click="saveOffer($event)" accesskey="S"></button>
    

    然后将jQuery.Event 传递给回调:

    【讨论】:

    • ...除了这正是 OP 试图不做的事情,除非我疯了。这篇文章的重点是访问 $event 而不显式传递它......这似乎正是你在这里所做的。
    • 我(另一方面)可以忍受它
    • 在谷歌搜索如何传递 $event 后结束了这里。与其他支持者类似,没有阅读原始问题:-|
    【解决方案3】:

    正如其他人所说,你实际上不能严格按照你的要求去做。也就是说,Angular 框架可用的所有工具实际上也可供您使用!这意味着您实际上可以编写自己的元素并自己提供此功能。我写了其中一个作为示例,您可以在以下 plunkr (http://plnkr.co/edit/Qrz9zFjc7Ud6KQoNMEI1) 中看到。

    其中的关键部分是我定义了一个“可点击”元素(如果您需要旧版 IE 支持,请不要这样做)。在看起来像这样的代码中:

    <clickable>
      <h1>Hello World!</h1>
    </clickable>
    

    然后我定义了一个指令来获取这个可点击元素并将它变成我想要的(自动设置我的点击事件的东西):

    app.directive('clickable', function() {
        return {
            transclude: true,
            restrict: 'E',
            template: '<div ng-transclude ng-click="handleClick($event)"></div>'
        };
    });
    

    终于在我的控制器中,我准备好了点击事件:

    $scope.handleClick = function($event) {
        var i = 0;
    };
    

    现在,值得说明的是,它硬编码了处理点击事件的方法的名称。如果您想消除这种情况,您应该能够为指令提供单击处理程序的名称和“tada”——您有一个可以使用的元素(或属性),而不必再次注入“$event”。

    希望有帮助!

    【讨论】:

    • 你必须让handleClick事件可以被传入,伙计:)
    【解决方案4】:

    我不建议这样做,但您可以覆盖 ngClick 指令来执行您要查找的操作。这不是说,你应该。

    考虑到最初的实现:

    compile: function($element, attr) {
      var fn = $parse(attr[directiveName]);
      return function(scope, element, attr) {
        element.on(lowercase(name), function(event) {
          scope.$apply(function() {
            fn(scope, {$event:event});
          });
        });
      };
    }
    

    我们可以这样做来覆盖它:

    // Go into your config block and inject $provide.
    app.config(function ($provide) {
    
      // Decorate the ngClick directive.
      $provide.decorator('ngClickDirective', function ($delegate) {
    
        // Grab the actual directive from the returned $delegate array.
        var directive = $delegate[0];
    
        // Stow away the original compile function of the ngClick directive.
        var origCompile = directive.compile;
    
        // Overwrite the original compile function.
        directive.compile = function (el, attrs) {
    
          // Apply the original compile function. 
          origCompile.apply(this, arguments);
    
          // Return a new link function with our custom behaviour.
          return function (scope, el, attrs) {
    
            // Get the name of the passed in function. 
            var fn = attrs.ngClick;
    
            el.on('click', function (event) {
              scope.$apply(function () {
    
                // If no property on scope matches the passed in fn, return. 
                if (!scope[fn]) {
                  return;
                }
    
                // Throw an error if we misused the new ngClick directive.
                if (typeof scope[fn] !== 'function') {
                  throw new Error('Property ' + fn + ' is not a function on ' + scope);
                }
    
                // Call the passed in function with the event.
                scope[fn].call(null, event);
    
              });
            });          
          };
        };    
    
        return $delegate;
      });
    });
    

    然后你会像这样传递你的函数:

    <div ng-click="func"></div>
    

    相对于:

    <div ng-click="func()"></div>
    

    jsBinhttp://jsbin.com/piwafeke/3/edit

    就像我说的,我建议这样做,但这是一个概念证明,向您展示,是的 - 您实际上可以覆盖/扩展/增强内置角度行为以满足您的需求。无需深入挖掘原始实现。

    如果您决定走这条路,请谨慎使用它(不过这很有趣)。

    【讨论】: