【问题标题】:Why is YUI.add required when specifying YUI modules and if it is required how can non-YUI modules work?为什么在指定 YUI 模块时需要 YUI.add,如果需要,非 YUI 模块如何工作?
【发布时间】:2013-08-07 17:25:09
【问题描述】:

我们使用 YUI3 加载器来管理加载我们的 javascript 和 css 文件。作为每个页面上的引导 js 代码的一部分,我们有如下内容:

YUI({
  ...
  groups: {
     ... 
     myGroup: {
         modules: {
             "my-module": {
                 ...
                 path: "MyModule.js",
                 requires: [ "yui-base" ]
             },
         }
         ...
     }
  }
}).use("my-module", function (Y) {
    Y.MyModule.doStuff();
});

MyModule.js 有如下内容:

YUI.add('my-module', function (Y) {
    Y.MyModule = function () {
        ...
        _validator: Y.Lang.isString
    };
}, '3.4.0', {
    requires: [ "yui-base" ]
});

YUI 还声称 here 加载器可以与非 YUI3 “模块”一起使用,因为它们在配置中指定了它们的依赖关系。他们为 yui2 组提供了以下示例模块配置:

       yui2: {
           combine: true,
           base: 'http://yui.yahooapis.com/2.8.0r4/build/',
           comboBase: 'http://yui.yahooapis.com/combo?',
           root: '2.8.0r4/build/',
           modules:  { // one or more external modules that can be loaded along side of YUI
               yui2_yde: {
                   path: "yahoo-dom-event/yahoo-dom-event.js"
               },
               yui2_anim: {
                   path: "animation/animation.js",
                   requires: ['yui2_yde']
               }
           }
       }

这表明 YUI 足够聪明,只有在 yahoo-dom-event.js 加载并运行后才能加载和运行 YUI2 的 animation.js。

我不明白的是,如果这适用于非 YUI 模块,为什么我必须用 YUI.add 和冗余需求列表包装我自己的模块(因为在配置中也指定了需求)?

我尝试删除添加包装器(我将其替换为(function (Y) { /* module content */ })(YUI);),但这会导致页面加载时出现 js 错误:Y.Lang 未定义。因此,似乎在没有包装 add() 调用的情况下,脚本在定义 Y.Lang 的基本 yui 脚本之前执行。但是,如果是这样的话,那么这对于非 YUI 模块(不调用 YUI.add())不会是个问题吗?

【问题讨论】:

    标签: javascript yui yui3


    【解决方案1】:

    区分使用 YUI3 功能(沙盒化 Y.Lang 等)的自定义模块和完全外部代码非常重要。

    在第一种情况下,YUI.add() 包装器始终是必需的,因为沙箱 Y 变量在模块回调(YUI.add() 的第二个参数)之外不可用。不幸的是,由于Y.Loader(发生组合加载魔术的地方)的限制,在手写模块中重复模块配置是必要的。使用 YUI 的 build tools 的模块会自动添加包装器和元数据。

    使用完全外部代码,您只需要提供fullpath 配置属性,YUI 就会做正确的事情。在内部,YUI 知道给定的<script> 请求何时完成,并将该成功与配置的模块名称相关联。

    为了简单起见,我将使用YUI.applyConfig 来演示配置位。使用它,您可以创建任意数量的 YUI 沙箱(通过YUI().use(...)),并混合配置,而不是到处重复。

    YUI.applyConfig({
        "modules": {
            "leaflet": {
                "fullpath": "http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"
            },
            "my-leaflet-thing": {
                "path": "path/to/my-leaflet-thing.js",
                "requires": [
                    "base-build",
                    "node-base",
                    "leaflet"
                ]
            }
        }
    });
    

    my-leaflet-thing.js 看起来像这样:

    YUI.add("my-leaflet-thing", function (Y) {
        // a safe reference to the global "L" provided by leaflet.js
        var L = Y.config.global.L;
    
        Y.MyLeafletThing = Y.Base.create("myLeaflet", Y.Base, {
            initializer: function () {
                var id = this.get('node').get('id');
                var map = L.map(id);
                // etc
            }
        }, {
            ATTRS: {
                node: {
                    getter: Y.one
                }
            }
        });
    
    // third argument is a version number,
    // but it doesn't affect anything right now
    }, "1.0.0", {
        "requires": [
            "base-build",
            "node-base",
            "leaflet"
        ]
    });
    

    鉴于此设置,由于这需要一个非异步库,您可以安全地执行此操作:

    YUI().use("my-leaflet-thing", function (Y) {
        var instance = new Y.MyLeafletThing({
            "node": "#foo"
        });
    });
    

    注意:如果外部文件自己动态加载(例如,async Google Maps API),YUI 将只知道初始请求成功,而不是加载的整个文件链。为了解决这个问题,您需要在 fullpath 配置中使用查询字符串回调参数,该参数与需要它的模块中的一些全局公开回调相关联。

    在这些情况下,最好使用内部Y.use()(注意沙盒变量)来更好地封装所需的全局变量。

    配置:

    YUI.applyConfig({
        "modules": {
            "google-maps-api": {
                "fullpath": "http://maps.googleapis.com/maps/api/js" +
                                "?v=3&sensor=false&callback=initGMapsAPI"
            },
            "my-google-map-thing": {
                "path": "path/to/my-google-map-thing.js",
                "requires": [
                    "base-build",
                    "node-base"
                ]
            }
        }
    });
    

    my-google-map-thing.js:

    YUI.add("my-google-map-thing", function (Y) {
        // publish a custom event that will be fired from the global callback
        Y.publish('gmaps:ready', {
            emitFacade: true,
            fireOnce: true
        });
    
        // private sentinel to determine if Y.use() has been called
        var isUsed = false;
    
        // expose global function that matches "callback" parameter value
        Y.config.global.initGMapsAPI = function () {
            // Y.config.global.google is now available
            Y.fire('gmaps:ready');
        };
    
        Y.MyGoogleMapThing = Y.Base.create("myGoogleMap", Y.Base, {
            initializer: function () {
                Y.on('gmaps:ready', this.render, this);
                if (!isUsed) {
                    isUsed = true;
                    Y.use("google-maps-api");
                }
            },
            render: function () {
                // safe reference to global "google"
                var google = Y.config.global.google;
                var id = this.get('node').get('id');
                var map = new google.maps.Map(id, {
                    // ...
                });
                // etc
            }
        }, {
            ATTRS: {
                node: {
                    getter: Y.one
                }
            }
        });
    
    }, "1.0.0", {
        "requires": [
            "base-build",
            "node-base"
        ]
    });
    

    总结一下:YUI.add() 只有在编写依赖于 YUI3 沙盒资源的模块时才需要。加载外部代码,只要它是同步的,就像使用 fullpath 配置属性一样简单。异步外部加载有点麻烦,但还是可以的。

    【讨论】:

    • 所以如果我理解正确,你需要 add() 来使用沙盒模块的原因是 add 回调不会被同步调用,因此如果你尝试使用像 Lang 这样的模块在初始脚本执行期间同步,它还没有被定义。
    • 没错!基本上,YUI.add() 是在 YUI 的全局注册表中以指定名称注册模块回调。 YUI().use() 获取您传递的模块名称列表并将它们附加到它创建的沙箱(回调的 Y 参数)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 2015-04-07
    • 2014-05-30
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多