在 AngularJS 中的 ng-click 上获取 PointerEvent 而不是 jQuery.Event

Getting PointerEvent instead of jQuery.Event on ng-click in AngularJS

我正在将 AngularJS 的旧代码库从数百个 <script> 标记迁移到 es 模块(我提到这一点的唯一原因是因为它可能会提供一些见解为什么我会出现这种奇怪的行为)。

我发现在旧的代码库中(以及 Whosebug 中的所有其他地方),给定一个带有 $event 的 ng-click,一个 jQuery.Event 被注入到回调中:

<button ng-click="doX($event)">Click me</button>
$scope.doX = ($event) => {
  console.log($event); // $event: jQuery.Event
};

但是,在新代码库(我使用的是 Vite)中,我得到的是 $event: PointerEvent

这是怎么解释的?它是否检查全局变量声明以决定是否用 jQuery?

包装原始事件

See Playground

调试 angular.js 的源代码后,我发现这些行引导我找到解决方案

function bindJQuery() {
    // ...
  
    // bind to jQuery if present;
    var jqName = jq();
    jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
             !jqName             ? undefined     :   // use jqLite
                                   window[jqName];   // use jQuery specified by `ngJq`
  
    // Use jQuery if it exists with proper functionality, otherwise default to us.
    // AngularJS 1.2+ requires jQuery 1.7+ for on()/off() support.
    // AngularJS 1.3+ technically requires at least jQuery 2.1+ but it may work with older
    // versions. It will not work for sure with jQuery <1.7, though.
    if (jQuery && jQuery.fn.on) {
      jqLite = jQuery;
      extend(jQuery.fn, {
        scope: JQLitePrototype.scope,
        isolateScope: JQLitePrototype.isolateScope,
        controller: /** @type {?} */ (JQLitePrototype).controller,
        injector: JQLitePrototype.injector,
        inheritedData: JQLitePrototype.inheritedData
      });
    } else {
      jqLite = JQLite;
    }
  
    // ...
  }

基本上,angular.js 是在全局 window 变量中寻找 jQuery。由于我们使用的是 ES 模块,我们不能只在代码的开头放置 window.$ = jQuery

快速解决方案

在您的 index.html 文件中全局导入 jQuery。

更好的解决方案

因为我正在使用 Vite,所以我创建了一个插件,允许我修改 angular.js 文件的源代码。我在顶部文件中添加了以下行:

import $ from "jQuery";
window.jQuery = $;

我在维护源映射时采用的方法是使用 recast

步骤

  1. 创建名为 vite-plugin-third-party-modifiers.ts 的文件:
import { PluginOption } from "vite";
import recast from "recast";

export function thirdPartyModifierPlugin(): PluginOption {
  return {
    name: "third-party-resolvers",

    transform(src, id) {
        const fileName = id.split(/[/]+/).pop().split("?")[0];

        if (fileName === "angular.js") {
            const ast = recast.parse(src);
            const b = recast.types.builders;

            // adds: window.$ = jQuery
            ast.program.body.unshift(
                b.importDeclaration(
                  [b.importDefaultSpecifier(b.identifier("jQuery"))],
                  b.literal("$")
                )
              );

            // adds: import $ from "jquery"
            ast.program.body.unshift(
                b.expressionStatement(
                  b.assignmentExpression(
                    "=",
                    b.memberExpression(b.identifier("window"), b.identifier("$")),
                    b.identifier("jquery")
                  )
                )
              );

            return recast.print(ast);
        }

        return null;
    },
  };
}
  1. vite.config.js
  2. 中导入此插件
export default defineConfig({
  // ...
  plugins: [
    thirdPartyModifierPlugin(),
  ],
  // ...
});