一步步学会使用SeaJS 2.0

本文分为以下8步,熟悉之后就能够熟练使用SeaJS,从此之后你的生活会变得更加轻松愉悦!
1、SeaJS是什么?
2、下载并检阅SeaJS
3、建立工程和各种目录
4、引入SeaJS库
5、编写自己的代码
6、引入自己的代码
7、压缩合并
8、总结展望


--------------------------------------------------


1、SeaJS是什么?


你一定听过前端模块化开发吧?神马,你没听过?我只能说你out了……
你应该知道Java的import吧?神马,你又不知道?那你应该知道CSS中的import吧……
在这里我不想展开说前端模块化的含义和价值,因为这里有一篇好文( https://github.com/seajs/seajs/issues/547),详细说明了前端模块化。

我知道你看到那么长的文章肯定会望而却步,也许你是希望能够快速开始敲代码(程序员的通病……)。没关系,如果实在读不下去,只要记住模块化要解决的问题即可:命名冲突、文件依赖关系。

这两个闹心的问题应该遇到过吧,如果没遇到过……我只能说你太牛X了

好了,前端模块化就扯到这里,写过前端的人应该基本都知道JavaScript自身是不支持模块化开发的,所以就有了SeaJS这款神器,为前端从业者提供了一个强大易用的模块化开发工具。




2、下载并检阅SeaJS


SeaJS现在已经是2.0版本啦,到这里下载: https://github.com/seajs/seajs


解压后会看到下列目录:


其中:
dist —— 压缩好的、用于浏览器端的SeaJS代码
docs —— 文档
src —— 源代码
package.json + Gruntfile.js —— Grunt构建工具所需要的文件,这个在第七步压缩合并会介绍到
其他目录或文件可以暂且不管




3、建立工程和各种目录


准备工作已经完成,我们终于可以开始进行开发啦!来,跟我走:
a. 建立工程
用你最喜欢的IDE建立工程,名字为HelloSeaJS
b. 准备各种目录
在这里把JavaScript、Image、CSS都放在统一的资源文件(assets)中,建好之后的目录如下:

(我使用了Sublime2.0,在这里强烈推荐)


c. 把刚刚下好的seajs/dist中的文件都放在scripts/seajs目录下

注意:SeaJS会根据自身的URI来决定URL base,而SeaJS在加载其他模块的时候会根据这个URL base来计算路径。SeaJS会忽略掉seajs、seajs/2.0.0/seajs这两种目录,照上述的目录结构,此处的URL base就是HelloSeaJS/assets/scripts,这样其他模块就可以与seajs目录并行存放。


至此,工程和文件都已准备完成。




4、引入SeaJS库


与引入其他js库并无太大区别:
<script src="assets/scripts/seajs/sea.js" id="seajsnode"></script>
你可能注意到,这里加上了id="seajsnode",原因如下:
a. SeaJS加载自身的script标签的其他属性(如data-config、data-main)等来实现不同的功能

b. SeaJS内部通过document.getElementById("seajsnode")来获取这个script标签(其实SeaJS内部还有一种方式,不过另一种方式的效率比较低,所以不推荐,如果有兴趣,可以看一下源码https://github.com/seajs/seajs/blob/master/src/util-path.js





5、编写自己的代码


这里作为示范,只做了一个非常简单的效果,点击查看: http://liuda101.github.io/HelloSeaJS/
在编写自己代码的时候,要时刻记住”模块化“,而操作起来也非常简单,因为在SeaJS中一个文件就是一个模块。
下面是代码逻辑的模块application.js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
define( function (require,exports,module){
    
      var  util = {};
    
      var  colorRange = [ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' ];
    
      util.randomColor =  function (){
           return  '#'  +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)];
      };
    
    
      var  helloSeaJS = document.getElementById( 'hello-seajs' );
      helloSeaJS.style.color = util.randomColor();
      window.setInterval( function (){
           helloSeaJS.style.color = util.randomColor();
      },1500);
});

我们看到,所有代码都放在define(function(require,exports,module){});函数体里面。
define是SeaJS定义的一个全局函数,用来定义一个模块。
至于require,exports,module都是什么,可以暂且不管,到此,我们的代码已经完成,很简单吧。嗯,花个几十秒钟,看一下代码。
……
看完之后,你会说,这算什么啊!这就完了么?
不要怪我,为了简单易懂,我们就按照”一步步“的节奏慢慢来。

随着代码的增多,你肯定会遇到util越来越多的情况。很好,这样看来,我们就有了两个模块:util模块和application模块。SeaJS中,文件即模块,所以当然要将其分为两个文件。先看util.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
define( function (require,exports,module){
      var  util = {};
    
      var  colorRange = [ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' ];
    
      util.randomColor =  function (){
           return  '#'  +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)] +
                colorRange[Math.floor(Math.random() * 16)];
      };
    
      module.exports = util;
});


除了define之外,我们看到module.exports = util;这一句比较特殊。这句是在说,我util模块向外暴露的接口就这些,其他所有的东西都是我内部用的,尔等就无需担心了,我会照顾好的。

再看application.js:

1
2
3
4
5
6
7
8
9
10
define( function (require,exports,module){
    
      var  util = require( './util' );
    
      var  helloSeaJS = document.getElementById( 'hello-seajs' );
      helloSeaJS.style.color = util.randomColor();
      window.setInterval( function (){
           helloSeaJS.style.color = util.randomColor();
      },1500);
});


我们看到var util = require('./util');这句比较特殊。这句就是在说,我application模块由于业务需要,想请util模块来帮忙,所以把util给require进来。



至此,我们经历了一个模块到两个模块的转变,在日后漫长的日子中,我们的模块也许会越来越多,不过不用担心,有了SeaJS提供的define、require、module.exports,我们都可以方便的应对。




6、引入自己的代码


你看到这个小标题,你可能会极力的鄙视我,这等工作还需要你来示范?于是,你啪啪啪啪,在引入SeaJS的script标签后引入了util.js和application.js:
<script src="assets/scripts/application/util.js"></script>
<script src="assets/scripts/application/application.js"></script>
然后你不停的F5……

你看不到效果吧?这就是这个小节存在的理由。


SeaJS提供了模块化的能力,前面我们已经看到了SeaJS定义模块、引用模块的方法,而这里就要用到SeaJS加载并启动模块的两种方式:
a、使用data-main
为<script src="assets/scripts/seajs/sea.js" id="seajsnode"></script>添加data-main="application/application"属性即可:
<script src="assets/scripts/seajs/sea.js" id="seajsnode" data-main="application/application"></script>
SeaJS会根据data-main指定的模块来作为整个应用的入口模块。SeaJS找到这个模块之后,就会加载执行这个模块对应的文件。
那么,SeaJS又是怎么找到这个文件呢?也就是说,这个模块对应的加载路径是多少?
“算法”是:SeaJS_URL_base + data-main
如上文,该例子的SeaJS_URL_base是HelloSeaJS/assets/scripts/

那么,加载路径就是HelloSeaJS/assets/scripts/application/application.js(SeaJS会自动加上.js后缀)


b、使用seajs.use
在<script src="assets/scripts/seajs/sea.js" id="seajsnode">后面加上:
<script> seajs.use("application/application"); </script>
其实这两种效果在这个例子中是一样的,data-main通常用在只有一个入口的情况,use可以用在多个入口的情况,具体用法,看这里: https://github.com/seajs/seajs/issues/260

如果你对你的程序有完全的控制权,建议使用data-main的方式,这样整个页面就只有一段script标签!作为一名前端开发人员,我不得不惊叹:干净、完美!


无论使用哪种方式,跟着我一起F5一下!
在打开Chrome的debug工具,查看Network这个tab:


我们看到,SeaJS已经帮我们加载好了application.js和util.js,舒服吧~
嗯,我第一次试用SeaJS的时候,到这里也感到了无比的舒心




7、压缩合并


正当我伸伸懒腰,打算上个厕所的时候,突然想到一件事情:如果模块越来越多,那么多文件都要分开加载?那岂不严重影响性能!?(啥,你不知道为啥?)
要压缩合并JavaScript呀!于是,我强忍住那股液体,开始用YUICompressor来压缩,并手动合并了两个文件。
这里就不展示结果了,因为很蛋疼,完全对不住我刚才忍住液体的勇气!结果当然是,失败。
为什么会失败呢?自己想了想,同时打开压缩后的代码一看,才发现原因:

压缩后之后,require变量变成了a变量。SeaJS是通过require字面来判断模块之间的依赖关系的,所以,require变量不能被简化。


嗯,SeaJS已经替我们想到了这个问题,于是我们就采用SeaJS提供的方式来合并压缩吧(当然你也可以自己用别的方式压缩)。

SeaJS在2.0之前,是采用SPM作为压缩合并工具的,到了2.0,改为Grunt.js,SPM变为包管理工具,类似NPM(不知道NPM?Google一下吧)


自动化不仅是科技带给社会的便利,也是Grunt带给前端的瑞士军刀。使用Grunt,可以很方便的定制各种任务,如压缩、合并等。使用Grunt之前,需要安装node环境和grunt工具,Google一下,十分钟后回来。

……


Grunt最核心的就两个部分,package.json、Gruntfile.js。


a. package.json

    Grunt把一个项目/目录视为一个npm模块,package.json就是用来描述这个模块的信息,包括name、version、author等等。
这里强调一下,Grunt既然将该目录视为一个模块,那么该模块当然可以依赖其他模块。
我们看本示例的:
1
2
3
4
5
6
7
8
9
10
11
12
{
      "name" : "HelloSeaJS",
      "version" : "1.0.0",
      "author" : "Qifeng Liu",
      "devDependencies" : {
           "grunt" : "0.4.1",
           "grunt-cmd-transport" : "0.1.1",
           "grunt-cmd-concat" : "0.1.0",
           "grunt-contrib-uglify" : "0.2.0",
           "grunt-contrib-clean" : "0.4.0"
      }
}



devDependencies就是用来描述自身所依赖的模块
其中:
grunt模块用来跑Gruntfile.js中定义的任务
grunt-cmd-transport模块用来对SeaJS定义的模块进行依赖提取等任务
grunt-cmd-concat模块用来对文件进行合并
grunt-contrib-uglify模块用来压缩JavaScript

grunt-contrib-clean模块用来清除临时目录


b. Gruntfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
module.exports =  function (grunt){
    
      grunt.initConfig({
           transport : {
                options : {
                     format :  'application/dist/{{filename}}'   //生成的id的格式
                },
                application : {
                     files : {
                          '.build'  : [ 'application.js' , 'util.js' ]    //将application.js、util.js合并且提取依赖,生成id,之后放在.build目录下
                     }
                }
           },
           concat : {
                main : {
                     options : {
                          relative :  true
                     },
                     files : {
                          'dist/application.js'  : [ '.build/application.js' ],   // 合并.build/application.js文件到dist/application.js中
                          'dist/application-debug.js'  : [ '.build/application-debug.js' ]
                     }
                }
           },
           uglify : {
                main : {
                     files : {
                          'dist/application.js'  : [ 'dist/application.js' //对dist/application.js进行压缩,之后存入dist/application.js文件
                     }
                }
           },
           clean : {
                build : [ '.build' //清除.build文件
           }
      });
    
      grunt.loadNpmTasks( 'grunt-cmd-transport' );
      grunt.loadNpmTasks( 'grunt-cmd-concat' );
      grunt.loadNpmTasks( 'grunt-contrib-uglify' );
      grunt.loadNpmTasks( 'grunt-contrib-clean' );
    
      grunt.registerTask( 'build' ,[ 'transport' , 'concat' , 'uglify' , 'clean' ])
};


定义好两个文件之后,就可以进入到application目录下,首先运行:
npm install
该命令会下载好package.json中依赖的模块
然后运行
grunt build

该命令会运行grunt.registerTask方法中指定的任务


不出差错的话,会在application目录下生成一个dist目录,里面包含了合并但没压缩的application-debug.js和合并且压缩好的application.js。
修改index.html的
<script src="assets/scripts/seajs/sea.js" id="seajsnode" data-main="application/application"></script>
<script src="assets/scripts/seajs/sea.js" id="seajsnode" data-main="application/dist/application"></script>
大功告成!




8、总结展望


SeaJS秉着简单实用的原则,API设计职责单一,使用起来得心应手。
SeaJS为前端提供了模块化能力,可以简单优雅的解决命名冲突、依赖关系等常见且棘手的问题。通过使用SeaJS,我的生活质量一下次上升好几个档次。
当然,除了本文介绍的,SeaJS还有一些其他功能,相信只要你入了门,肯定能够迅速掌握,这里给个链接 http://seajs.org/docs/#docs
其实,许多语言自身已经有了模块化的功能,如Java的import,C++的#include等,但是由于各种原因,JavaScript自身并没有这个功能。虽然借助于SeaJS可以很方便的进行模块化开发了,但总觉得这个能力应该是语言自身的。好在,下个版本的JavaScript貌似在计划引入模块化的概念,让我们拭目以待吧!




最后,感谢SeaJS作者玉伯。



PS,本文参考了SeaJS提供的使用范例https://github.com/seajs/examples/tree/master/static/hello

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: jfinal2.0是一款基于Java语言的轻量级开源Web应用框架。它具有简单易用、快速开发、高效稳定等特点。采用了MVC架构模式,通过注解方式配置路由,可以实现快速、灵活地进行控制器的映射。同时,它也支持AOP、ORM等常用的开发模式,通过简化繁琐的代码操作,提高了开发效率。 bootstrap是一款HTML、CSS和JavaScript框架,用于开发响应式、移动设备优先的网站和Web应用。它提供了丰富的CSS样式和JavaScript插件,可以快速搭建出漂亮的、兼容性良好的界面。同时,bootstrap还支持自定义主题、响应式布局等功能,非常适合用于快速构建用户友好的界面。 seajs是一款用于JavaScript模块化开发的框架。它采用了CMD规范,通过define和require等方法对模块进行定义和引用。seajs可以帮助开发人员管理和加载模块,实现代码的模块化,提高了代码的可维护性和复用性。除此之外,seajs还支持插件机制、异步加载等功能,更好地适应了复杂的Web应用开发需求。 fullcalender.js是一款基于JavaScript和jQuery的全功能日历插件。它提供了丰富的功能,如日程管理、事件编辑、拖拽操作等。同时,fullcalender.js还支持各种视图模式的切换,如月、周、日视图,并且支持自定义样式和事件处理函数,可以方便地适应各种日历需求。使用fullcalender.js可以使用户在Web应用中更加方便地管理和查看日期和事件信息。 ### 回答2: jfinal2.0是一种基于Java的轻量级MVC框架,它具有简单易用、高效快速的特点。通过JFinal2.0,开发人员可以快速搭建Java Web应用程序,并且具有良好的扩展性和灵活性。 Bootstrap是一种前端开发框架,它提供了丰富的组件和样式,可以帮助开发人员快速构建美观且响应式的网页。通过Bootstrap,开发人员可以使用预定义的样式和布局,使网页在不同的设备上显示效果一致。 Seajs是一种模块加载器,它可以帮助开发人员更好地组织和管理JavaScript代码。通过Seajs,开发人员可以将代码分割成独立的模块,通过异步加载的方式进行模块依赖管理,提高前端开发的效率。 FullCalendar.js是一种用于显示和操作日历的JavaScript库。它可以帮助开发人员在网页中嵌入交互式的日历控件,并且支持事件的添加、编辑和删除等功能。通过FullCalendar.js,开发人员可以轻松实现日历功能,例如会议安排、活动管理等。 综上所述,jfinal2.0、bootstrap、seajs和fullcalender.js都是在不同场景中用于简化开发工作的工具和框架。它们可以使开发人员更高效地开发应用程序,并提供了丰富的功能和易用的界面,为用户提供更好的体验。 ### 回答3: JFinal 2.0是一款基于Java语言的开源Web开发框架,它提供了简单易用的API和插件机制,可以帮助开发者快速构建高性能的Web应用程序。JFinal 2.0具有轻量级和灵活的特点,拥有良好的MVC架构和面向切面编程的支持。它还提供了丰富的插件来扩展应用的功能,例如插件管理、权限控制、缓存管理等。JFinal 2.0还集成了Bootstrap、Sea.js和FullCalendar.js等优秀的前端框架和组件,使开发者可以更方便地实现各种前端交互效果和页面布局。 Bootstrap是一款开源的前端框架,它提供了丰富的CSS和JavaScript组件,能够帮助开发者快速构建响应式的Web页面。Bootstrap具有简洁美观的设计风格和灵活的布局系统,可以适应不同屏幕大小的设备,并提供了丰富的样式和组件,例如按钮、表单、导航条等,可以帮助开发者快速构建出现代化的Web界面。 Sea.js是一款用于浏览器端JavaScript模块化开发的工具。它采用的是CMD规范,可以将JavaScript代码按照模块化的方式进行组织和管理,提供了便捷的模块定义和加载机制。Sea.js还提供了丰富的插件系统和调试工具,可以帮助开发者更高效地进行JavaScript开发。 FullCalendar.js是一款功能强大的日历插件,它基于jQuery开发,提供了丰富的日历展示和日程管理功能。FullCalendar.js可以将日历事件以可视化的方式展示,并支持日程的拖拽和编辑功能,可以方便地进行日程的增删改查操作。FullCalendar.js还提供了多种日历视图和自定义配置选项,可以适应不同的日程管理需求。 综上所述,JFinal 2.0结合Bootstrap、Sea.js和FullCalendar.js等前端框架和组件,可以帮助开发者高效地构建性能优越、界面美观、功能丰富的Web应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值