最近在用RequireJS写一个可复用的UI组件。这个组件会利用RequireJS的模块依赖机制来加载所需的js文件,全部加载结束后,建立一个全局的入口函数供第三方使用,同时触发一个全局的事件,通知第三方入口函数已可以使用了。基本原理如下:

// main.js

requirejs(['app/ui'], function(ui) {
  window.showUI = function(container) {   // 注册全局入口函数
    $(container).showUI();
  };
  
  $(document).trigger('uiloaded');  // 通知调用者入口函数可用
});

// app/ui.js

define(['jquery', 'mustache'], function($, mustache) {
  ...
});

但在第三方调用时发现,第三方监听事件uiloaded总是失败,具体来说,虽然监听了uiloaded,但事件触发时却无法执行第三方的处理函数。即

// caller.html
$(function() {
  $(document).on('uiloaded', function() {
    showUI("#container");  // 该函数无法被触发
  });
});

反复调试后发现,有可能是app/ui.js中重新加载了jQuery,导致调用者加载的jQuery失效,从而调用者在加载RequireJS和这个组件之前监听事件的代码全部失效了。

那么解决方法就是让RequireJS复用调用者已加载过的jQuery,而不要自己重新加载。这篇文章里给出了一个绝妙的方法:

Load jQuery before RequireJS and still use it as dependency

简单来说,只需在我的main.js里定义如下代码:

define('jquery', [], function() {
  return jQuery;
});

这样RequireJS就不会重新加载jQuery,而是使用已有的jQuery对象了。