模块化开发一 seajs

模块化开发

随着团队开发的复杂化,我们依赖的代码库会越来越多;

安装

npm install spm -g
spm install seajs

可以安装:
安装bower
npm install -g bower
安装seajs
brwer install seajs
github:
http://github.com/seajs/seajs

也可以下载成一个js文件引入
<script src="../lib/sea.js"></script>
<script>
console.log(seajs.version)
</script>

知识

  • 前端这些模块管理的实现是基于AMD规范(异步、管理、加载规范),在最终实现的时候尊重commndjs规范(nodejs就是这个),定义模块时有两种,第一个是只传一个参数就是commndjs规范,传递多个参数的时候,写法尊重moduletransport规范;

  • 通常define只允许我们定义一个模块,当定义多个模块的时候,后面的会覆盖掉前面的;

seajs文件路径是以sea.js作为出发点的 , 如果是'./'则以自身文件夹为出发点

使用

建立一个de.js文件

seajs.use('de')

在控制面板networks里能看到de.js被加载进来了

define

当传递一个参数的时候,参数就是一个模块,参数可以是任意类型;

在de.js中:
console.log('hello')

index.html:
seajs.use('de',function(main){
})

控制台输出:hello 字符串

define传递:
de.js输入define('hello')

index.html:
seajs.use('de',function(main){
console.log(main)
})
控制台输出:hello 字符串

de.js输入

define({
    color:'red',
    say:function(){
        return 'hello'
    }
})

控制台输出一个对象

  • 如果不写在define里就是一个undefined

我们还可以传递函数,这是一种最复杂的方式,工作中基本是这种方法:

这个函数自带三个参数:
require:引用其它模块的工厂方法
exports:返回的接口对象
module:模块的module属性集
define(function(require,exports,module){
    return {
        color:'yellow'
    }
})
  • 当传递多个参数时,两个或者三个
    如果传递两个参数的时候,第一个参数表示该模块依赖的模块数组集合,最后一个参数是function;
    如果传递三个参数的时候,第一个表示模块的名称,第二个表示该模块依赖的模块集合,第三个参数就是个function;
define('main',[],function(require,exports,module){
    return {
        color:'yellow'
    }
})

模块的依赖

  • 包就是前段说的模块
  • 当传递模块名称的时候,模块的名称就是该名称,当不传递模块的名称的时候,该模块的名称就是该文件的名称,通常我们将模块的名称与文件的名称保持一致

我们再新建一个header.js文件:

define(function(){
    return {
        color:'orange'
    }
})

在main.js中引用:

define(function(require,exports,module){
    var header = require('./header/header');
    console.log(header)
    return {
        color:'yellow'
    }
})

index.html的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script src="js/sea.js"></script>
    <script>
        seajs.use('main',function(main){
            console.log(main)
        })
    </script>
</body>
</html>

控制台输出两个对象;

use


seajs.use(['header/header','header/skin/skin'],function(header,skin){
    console.log(header,skin)
})

第一个参数可以是一个字符串,也可以是一个模块数组,有多少个,在回调函数的参数就有多少个;

我们可以使用header:

define(function(require,exports,module){
    var header = require('./header/header');
    document.body.style.background = header.color;
    return {
        color:'yellow'
    }
})
  • require规范:
    1. require不能简写;
    2. require不能被重新定义;
      • 不能赋值 var req = requie;是不可以的
      • 不能定义函数 function require 是不可以的
      • 不能在子函数中的参数中使用require
      • 不能在子函数的作用域内重定义(重复上面三条)
    3. require的参数只能是完整的字符串,拼接也不行require('abc' + 'cde')是不可以的;
  • require的参数值如何定义:
    参数值表示的是文件的路径,相对于sea.js,当然也可以./从自身目录出发

项目目录:
- index.html
- js文件夹
- sea.js
- main.js
- header文件夹
- header.js
- skin文件夹
- skin.js
skin.js:

define(function(){
    return 'haha'
})

在main.js中引用:

define(function(require,exports,module){
    var header = require('./header/header');
    var skin = require('header/skin/skin')
    console.log(skin)
    document.body.style.background = header.color;
    return {
        color:'yellow'
    }
})

控制台输出:haha
require:

  • 可以看到是以sea.js为路径起始点,也就是根目录;
  • 加载js文件,后缀名不写;
    define:
    require,exports,module不能更改

前面说到定义一个模块的时候最好名字和文件名一样,默认不写模块名;

如果我们写了不一样的名字会怎么样呢?
header.js中:

define('haha',[],function(){
    return {
        color:'orange'
    }
})

可以看到模块的名字为haha,依赖为空数组,文件名是header.js

main.js:

define(['header/header'],function(require,exports,module){
    var a = require('haha');
    var skin = require('header/skin/skin')
    console.log(a,111)
    return {
        color:'yellow'
    }
})

可以看到控制台可以输出结果;
所以

  • define的数组参数为依赖的模块路径
  • require为引入的模块名字
  • 如果两者相同,就可以直接var header = require('header/header'),不要后缀名.js

exports

  • export是保留字,所以使用exports;
  • 表示模块的接口,
    第一种:直接对exports添加属性,如exports.color = 'red';
    第二种:通过module来定义,module.exports.color = 'yellow';
    第三种:通过module来定义,module.exports = {color: 'orange'};
    第四种:通过return来定义,return {color:'green'};

我们在一个模块中定义接口的时候,只能使用一种,不能混用,后面的会覆盖前面的;

我们不可以直接对exports赋值新对象

main.js

define(function(require,exports,module){
    var a = require('header/header')
    console.log(a)
})

header.js

define(function(require,exports,module){
    exports.color = 'red'
})

注意:使用exports接口的header模块,require,exports,module三个参数必须写上;

第二种方式header.js:

define(function(require,exports,module){
    module.exports.color = 'red'
})

第三种方式header.js:

define(function(require,exports,module){
    module.exports={
        color:'blue'
    }
})

第四种方式header.js:

define(function(require,exports,module){
    return {
        color:'white'
    }
})

module

我们console.log(module);
有四个属性:

  1. id 模块名 默认为路径一致 如果id不与uri一样则要分开引用
  2. uri 路径
  3. dependencies 依赖的模块 放在数组里
    deps 依赖的模块 放在对象里
  4. exports是我们返回的接口;

小案例

  • 项目根目录
    • index.html
    • js文件夹
      • main.js
      • sea.js
      • lib文件夹
        • dom.js
        • event.js
        • string.js

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <button id="btn">猜一猜</button>
    <div id="out"></div>
    <script src="js/sea.js"></script>
    <script>
        seajs.use('main',function(){})
    </script>
</body>
</html>

main.js:

define(function(require,exports,module){
    var Evt = require('lib/event');
    var Dom = require('lib/dom');
    var Str = require('lib/string')
    var msg = 'i don\'t know'
    Evt.on('btn','click',function(){
        Dom.html('out',Str.upper(msg))
    })
})

dom.js

define(function(){
    var Dom = {
        g: function(id){
            return document.getElementById(id);
        },
        html:function(id,html){
            if(html){
                this.g(id).innerHTML = html;
            }else{
                return this.g(id).innerHTML;
            }
        }
    }
    return Dom;
})

event.js

define(function(require,exports,module){
    var Dom = require('lib/dom')
    var Evt={
        on: function(id,type,fn){
            Dom.g(id)["on"+type] = fn;
        }
    }
    return Evt;
})

string.js

define(function(){
    var Str = {
        upper:function(str){
            return str.toUpperCase();
        }
    }
    return Str;
})
require.async异步调用,跟use方法很像,我们在页面初始化使用use异步加载模块,在模块内部想实现模块的异步加载,就要用require.async方法;

案例一:
header.js:

define(function(require,exports,module){
    return {
        color:'white'
    }
})

main.js:

define(function(require,exports,module){
    var header = require('header/header')
    return {
        color: header.color
    }
})

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        html,body{
            height:100%;
        }
    </style>
</head>
<body>
    <script src="js/sea.js"></script>
    <script>
        seajs.use('main',function(main){
            console.log(main)
        })
    </script>
</body>
</html>

就可以得到header的color为white;

如果采用require.async(第一个参数为字符串也可以是数组,第二个参数是回调函数),和use很像;

define(function(require,exports,module){
    // var header = require('header/header')
    var header = require.async('header/header',function(header){
        console.log(111,header)
    })
    return {
        color:header.color
    }
})
  • 再来看下面的代码:
var loadSkin = false;
    if(loadSkin){
        var skin = require('header/skin/shin')
    }else{
        var header = require('header/header')
    }

其实两个文件都会加载请求回来,但是skin打印是undefined
如果换成异步加载:

var loadSkin = false;
    if(loadSkin){
        var skin = require.async('header/skin/shin')
    }else{
        var header = require.async('header/header')
    }

可以看到不会执行的代码文件不会加载;

seajs.config({})

写在index.html seajs.use上面

seajs.config接收一个对象参数,用来配置一些选项参数的,接收一个对象,里面的属性值,就是我们配置的选项;

1. alias

alias:{
    util:'lib/unitl-2.0'
}

这个可以解决一个问题:lib里面版本库文件,如果在main.js,header.js等等一大堆文件中引用:

var util = require('lib/util-2.0');

如果一天这个文件升级到了2.1,那么就要去打开这些引用了它的文件去修改,就会造成麻烦,所以alias就是解决这个问题的;
在alias中把这个文件定义为util,在mainjs,headerjs等文件中要使用它,只需要

define(function(require,exports,module){
    var util = require('util');
    console.log(util)

})

这样如果文件版本升级,只需要更改alias里面的路径即可;

2. paths

paths:{
    m:'module/header'
}

如果我们要引用module/header下面的header.js

var header = require('module/header/header');

如果按照上面定义好了的路径,以后引用这个文件夹下的文件只需要:

var header = require('m/header')

3. vars

vars:{
    hd:'header'
}

如何使用:

// var a = require('module/header/skin/skin')

var a = require('module/{hd}/skin/skin')

如果:

vars:{
    hd:'header/skin'
}

var a = require('module/{hd}/skin')

通过{}来匹配

4. map

map:[
    ['.js','.min.js']
]

映射,把所有的js文件做匹配处理;
如果有文件打包后,文件名可能不同,可以通过这个来处理;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容