繁体   English   中英

将全局导入模块模式转换为 ES6 模块

[英]Converting global import module pattern to ES6 modules

在过去的几年里,我一直在使用 JavaScript 的全局导入方法。 通常使用一组实用程序函数进行包装并传递给另一个站点模块,该模块包含针对每个 Web 功能的单独函数:

(function(m, u, ui, w, a, $){

    // Example Module
    m.example = function(){
        // Do stuff, the m.example module gets auto initialized.
};

})(Site.modules = Site.modules || {}, Site.utils, Site.ui, Site.w, Site.anim, jQuery);

在这个示例中,我传递了我们添加到的模块、实用程序、用户界面对象(主要是 gsap 的别名)和其他东西,如 jQuery。

正如您所看到的,它会变得很大而且很混乱,尤其是在具有大量功能的大型网站上。

我想转向 ES6 和 NPM,虽然我已经看到了许多关于如何制作模块、如何导入模块、使用 NPM 引入模块的文章和示例,但我找不到一个示例或文章实际上把它拉在一起。

举个简单的例子。 我用 NPM 导入了 slick-carousel。 我有一个带有横幅轮播和推文轮播的单页网站。 我应该如何检查这些元素是否存在并初始化 2 个单独的轮播?

使用匿名闭包,我只需要一个单独的自动启动函数来查找一个 DOM 元素,然后用不同的选项初始化一个轮播。

编辑

以我当前的工作流程为例,我定义了一个站点对象,该对象具有多个重用的静态变量和一些跨站点重用的项目,例如动画变量、对窗口的引用、自动更新变量以访问视口属性等。

然后在每个构建的网站所独有的单独文件中,我有一个主文件,我在其中为网站上实现的每个功能块创建单独的“模块”。 利用页面中包含的 jQuery 和普通 JavaScript 插件以及 utils 和主要 js 文件。

实用程序.js

jQuery(document).ready(function($) {
    Site.init();
});


var Site = (function($) {

    // DOM caching
    var win = window;

    // Globals
    var w = {
        width:  win.innerWidth,
        height: win.innerHeight,
        scroll: win.pageYOffset
    };

    var ui = {
        fast: 0.2,
        slow: 0.4,
        step: 0.03,
        easeout: Power4.easeOut,
        easein: Power4.easeIn
    };

    function updateGlobals(){
        w.width  = win.innerWidth;
        w.height = win.innerHeight;
        w.scroll = win.pageYOffset;
    }

    win.addEventListener('resize', updateGlobals, true);
    win.addEventListener('scroll', updateGlobals, true);
    win.addEventListener('load', updateGlobals, true);

    return {
        init: function(){

            for (var prop in this.modules) {
                if ( this.modules.hasOwnProperty(prop) ) {
                    this.modules[prop]();
                }
            }

            for (var props in this.autoInits) {
                if ( this.autoInits.hasOwnProperty(props) ) {
                    var $selector = $(props);

                    if ($selector.length) {
                        this.autoInits[props]($selector);
                    }
                }
            }
        },
        ui: ui,
        w: w
    };

})(jQuery);

主文件

(function(m, $){

    m.homepageCarousel = function(){
        var element = $('.js-homepage-carouel');
        
        $(element).slick({
            dots: true,
            speed: 500,
            arrows: false
        });
    };

    m.productsCarousel = function(){
        var element = $('.js-products-carouel');
        
        $(element).slick({
            dots: false,
            speed: 500,
            arrows: true
        });
    };

    m.showcookieNotice = function(){
        ... example check cookies for marker and show cookie notice if not present.
    }

    ... rest of the websites js, maps, menus, custom reused items etc

})(Site.modules = Site.modules || {}, jQuery);

不要以“一切都是全球性的”的方式思考。 全局作用域是最大的 js 设计错误之一。 例如:

 var name = 1; console.log(name + 1); // 2, right? No, try it ...

我不认为全局范围是完全无用的,但它的用例非常有限。 您应该将其视为网页/服务器状态。 这意味着在最好的情况下它不应该包含任何代码(= 函数)。 您向全局范围公开的功能(代码)越多,您就越有可能在两个脚本之间进行错误的推断,而这些错误真的很难发现。 相反,您的代码应该封装自身。 它应该尽可能少地暴露和改变全局范围。 这意味着如果您想在页面的两个不同文件之间共享某个功能(例如menu.jsslider.js都需要一个Button类),那么该功能应该进入一个模块,然后由两个脚本导入。 所以每个单独的文件都应该在顶部有导入,在最后有导出,并且应该封装自己:

import {functionality1, functionality2} from "module";

let somevariable; // variables declared with let or const do not appear on the global scope, although they are "global"

不要害怕在同一页面的不同文件中多次导入相同的模块。 模块只加载一次,并且通过摇树(大多数 Bundler 如 Webpack 都这样做),仅仅包含来自大模块的一些函数甚至可能不会加载整个大模块,而只是加载其中的几个块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM