zoukankan      html  css  js  c++  java
  • 使用SeaJS实现模块化JavaScript开发(新)

    本文转自张洋,因为SeaJS更新版本很快,所以原文中很多地方不太适用,在这里发布一个更新版。

    前言

      SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。使用SeaJS可以提高JavaScript代码的可读性和清晰度,解决目前JavaScript编程中普遍存在的依赖关系混乱和代码纠缠等问题,方便代码的编写和维护。
    SeaJS本身遵循KISS(Keep it Simple,Stupid)理念进行开发,后续的几个版本更新也都是吵着这个方向迈进。

    如何使用SeaJS

    下载及安装在这里不赘述了,不了解的请查询官网。

    基本开发原则

    • 一切皆为模块:SeaJS中的模块概念有点类似于面向对象中的类--模块可以拥有数据和方法,数据和方法可以定义为公共或私有,公共数据和方法可以供别的模块调用。
    • 每个模块应该都定义在一个单独的js文件中,即一个对应一个模块。

    模块的定义和编写

    模块定义函数define

    SeaJS中使用define函数定义一个模块。define可以接收三个参数:

    /**
    * Defines a module.
    * @param {string=} id The module id.
    * @param {Array.|string=} deps The module dependencies.
    * @param {function()|Object} factory The module factory function.
    */
    fn.define = function(id, deps, factory) {
        //code of function…
    }
    
    

    define可以接收的参数分别是模块ID,依赖模块数组及工厂函数。

    • 如果只有一个参数,则赋值给factory
    • 如果有两个参数,第二个赋值给factory,第一个如果是数组则赋值给deps,否则赋值给id
    • 如果有三个参数,则分别赋值

    但是,包括SeaJS官网示例在内几乎所有用到define的地方都只传递一个工厂函数进去,类似于如下代码:

    define(function(require,exports,module){
        //code of the module
    })
    

    个人建议遵循SeaJS官方示例的标准,用一个参数的define定义模块。那么id和deps会怎么处理呢?

      id是一个模块的标识字符串,define只有一个参数时,id会被默认赋值为此js文件的绝对路径。如example.com下的a.js文件中使用define定义模块,则这个模块的ID会赋值为 http://example.com/a.js ,没有特别的必要建议不要传入id。deps一般也不需要传入,需要用到的模块用require加载即可。

    工厂函数factory解析

      工厂函数是模块的主体和重点。它的三个参数分别是:

    • require:模块加载函数,用于记载依赖模块
    • exports:接口点,将数据或方法定义在其上则将其暴露给外部调用
    • module:模块的元数据
      这三个参数可以根据需要选择是否需要显示指定。

    module是一个对象,存储了模块的元信息,具体如下:

    • module.id:模块的ID
    • module.dependencies:一个数组,存储了此模块依赖的所有模块的ID列表。
    • module.exports:与exports指向同一个对象

    三种编写模块的模式

    第一种是基于exports的模式:

    define(function(require,exports,module){
        var a=require('a');
        var b=require('b'); //引入模块
        
        var data1=1; //私有数据
        
        var fun1=function(){//私有方法
            return a.run(data1);
        }
        
        exports.data2=2; //公有数据
        
        exports.fun2=function(){
            return 'hello';
        }
        
    })
    

    上面是一种比较“正宗”的模块定义模式。除了讲公共数据和方法附加在exports上,也可以直接返回一个对象表示模块,如下面的代码与上面的代码功能相同:

    define(function(require){
        var a=require('a');
        var b=require('b'); //引入模块
        
        var data1=1;
        
        var fun1=function(){
            return a.run(data1);
        }
        
        return{
            data2:2,
            fun2:function(){
                return 'hello';
            }
        }
    })
    

    如果模块定义没有其他代码,只返回一个对象,还可以有如下简化写法:

    define({
        data2:2,
            fun2:function(){
                return 'hello';
            }
        })
    

    第三种写法对于定义纯JSON数据的模块非常合适。

    根据应用场景的不同,SeaJS提供了三个载入模块的API,分别是:seajs.use,require和require.async。

    seajs.use

    seajs.use主要用于载入入口模块。入口模块相当于C语言的main函数,同时也是整个模块依赖树的根。seajs.use
    的用法如下:

    //第一模式
    seajs.use('./a');
    //回调模式
    seajs.use('./a',function(a){
        a.run();
    })
    //多模块模式
    seajs.use(['./a','./b'],function(a,b){
        a.run();
        b.run();
    })
    

    其中多模块的用法和KISSY中的模块加载方法类似,不亏是一个人写的啊!
    一般seajs.use只用在页面载入入口模块,SeaJS会顺着入口模块解析所有依赖模块并将它们加载。如果入口模块只有一个,也可以通过给引入seajs的script标签加入“data-main”属性来省略seajs.use,例如一下写法:

    <!DOCTYPE HTML>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>TinyApp</title>
    </head>
    <body>
        <p class="content"></p>
        <script src="./sea.js" data-main="./init"></script>
    </body>
    </html>
    

    require

    require是seajs主要的模块加载方法,当在一个模块中需要用到其他模块时一般用require加载:

    var m=require('./a');
    

    require.async

    上文说过seajs会在html页面打开时通过静态分析一次性记载所有需要的js文件,如果想要某个js文件在用时才加载,可以使用require.async。
    这样只有在用到这个模块时,对应的js文件才会被下载,也就实现了JavaScript代码的按需加载。

    SeaJS的全局配置

    seajs提供了一个seaj.configd的方法可以设置全局配置,接收一个表示全局配置的配置对象,具体方法如下:

    seajs.config({
    base:'path',
    alias:{
        'app':'path/app/'
    },
    charset:'utf-8',
    timeout:20000,
    debug:false
    })
    

    其中,

    • base表示基址路径
    • alias可以对较长的常用路径设置缩写
    • charset表示下载js时script标签的charset属性。
    • timeout表示下载文件的最大时长,以毫秒为单位。

    Seajs如何与现有的JS库配合使用

    要将现有的JS库与seajs一起使用,只需根据seajs的模块定义规则对现有库进行一个封装。例如,下面是对jQuery的封装方法:

        define(function(){
        /*
        此处为jquery源码
        */
    
        })
    

    一个完整的例子:
    上文说了那么多,知识点比较分散,所以最后我打算用一个完整的SeaJS例子把这些知识点串起来,方便朋友们归纳回顾。这个例子包含如下文件:

    • index.html 主页面
    • sea.js
    • jquery.js
    • init.js init模块,入口模块,依赖data、jquery、style三个模块,又主页面载入
    • data.js data模块,纯json数据模块
    • style.css css样式表

    html:

    <!DOCTYPE HTML>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="content">
        <p class="author"></p>
    
        <p class="blog"><a href="#">Blog</a></p>
    </div>
    <script src="sea.js"></script>
    <script>
            seajs.use('init');
    </script>
    </body>
    </html>
    

    javascript:

    //init.js
    define(function(require, exports, module) {
        var $ = require('./jquery');
        var data = require('./data');
        var css = require('./style.css');
     
        $('.author').html(data.author);
        $('.blog').attr('href', data.blog);
    });
     
    //data.js
    define({
        author: 'ZhangYang',
        blog: 'http://blog.codinglabs.org'
    });
    

    css:

    .author{color:red;font-size:10pt;}
    .blog{font-size:10pt;}
    

    请注意:
    1.请讲jquery.js源码文件包含在seajs模块加载代码中;

    2.在Sea.js < 2.3.0版本之前是可以加载css文件的,新版本中此功能移除,为了兼容考虑,加载css功能将作为一个插件存在。

    使用方法

    • 可以在sea.js标签后引入这个插件使用
    • 也可以将插件代码混入sea.js当中
    • 和seajs-style的区别
      • seajs-css是使 Sea.js 能够加载一个css文件,和link标签一样
      • seajs-style是指提供一个seajs.importStyle方法用于加载一段 css 字符串
  • 相关阅读:
    Unity3D性能优化之资源导入标准和属性设置篇
    博客主题-Next风格
    Pytorch 搭建 LeNet-5 网络
    CIFAR数据集解读
    Mnist数据集解读
    博客主题——cnbook
    博客主题——element v2
    更换清华镜像源
    图像插值技术——双线性插值法
    PASCAL VOC2012数据集解读
  • 原文地址:https://www.cnblogs.com/depsi/p/5041962.html
Copyright © 2011-2022 走看看