命令

release install init server inspect

http://fis.baidu.com/fis3/docs/api/command.html

配置

media important ::package ::image ::text :js :css

http://fis.baidu.com/fis3/docs/api/config.html

配置API

fis.set() fis.get() fis.match() fis.media() fis.plugin()

http://fis.baidu.com/fis3/docs/api/config-api.html

全局属性 & 文件属性 & 插件属性

http://fis.baidu.com/fis3/docs/api/config-props.html

FIS3 常用配置

制定目录规范 部署远端测试机 异构语言 less 的使用 异构语言 sass 的使用 前端模板的使用 某些资源不产出 某些资源从构建中去除

http://fis.baidu.com/fis3/docs/api/config-commonly-used.html

glob

http://fis.baidu.com/fis3/docs/api/config-glob.html

FIS3 内置插件及配置

fis-optimizer-clean-css fis-optimizer-png-compressor fis-optimizer-uglify-js fis-spriter-csssprites fis3-deploy-local-deliver fis3-deploy-http-push fis3-hook-components fis3-packager-map

http://fis.baidu.com/fis3/docs/api/config-system-plugin.html

常用插件列表

parser 插件 preprocessor 插件 fis3-preprocessor-autoprefixer postprocessor 插件 optimizer 插件 package 插件 deploy 插件 hook 插件

http://fis.baidu.com/fis3/docs/common-plugin.html

插件库

http://fis.baidu.com/fis3/plugins.html

开发API

http://fis.baidu.com/fis3/api/index.html

官方例子

https://github.com/fex-team/fis3-demo

我的博客

Read More

前言

个人感觉就是用来规范格式化输出你的amd 代码,书写规范参考commonjs。

安装插件

需要安装2个插件

1
2
sudo npm install -g fis3-hook-amd
sudo npm install -g fis3-hook-commonjs

说明 https://www.npmjs.com/package/fis3-hook-amd

实战

项目准备

1
2
3
/amd-module
/static
/static/require.js

包下载地址 http://requirejs.org/

创建amd-module模块

/amd-module/center/order.js

1
2
3
4
5
6
7
8
9
10
define(function (require, exports, module) {

    var config = require("../system/config");
    console.log(config.serverip());

    exports.list = function(){
        return "产品列表...";
    };

});

/amd-module/system/config.js

1
2
3
4
5
6
7
define(function (require, exports, module) {

    exports.serverip = function () {
        return "127.0.0.1";
    };

});

/amd-module/system/cart.js

1
2
3
exports.hello = function () {
    return "hello";
};

调用app页面

/app/index.html

1
2
3
4
5
6
7
8
9
10
<script type="text/javascript" src="../static/require.js"></script>
<script type="text/javascript">
    require.config({
        baseUrl: "/",
    });

    require(["amd-module/center/order.js"], function(order){
        console.log(order.list());
    });
</script>

配置fis-conf.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
// 开启 amd 插件
fis.hook('amd');

// 指定哪些需要被格式化的模块js
fis.match('/amd-module/**/*.js', {
    isMod: true
    //release: '/static/$0'
});

// 需要排除的文件
fis.match('/static/require.js', {
    isMod: false
});

测试运行

fis3 release

查看被格式化的模块

amd-module/center/order.js

1
2
3
4
5
6
7
8
9
10
define('amd-module/center/order', ['require', 'exports', 'module', "amd-module/system/config"], function (require, exports, module) {

    var config = require("amd-module/system/config");
    console.log(config.serverip());

    exports.list = function(){
        return "产品列表...";
    };

});

amd-module/system/cart.js

1
2
3
4
5
6
7
define('amd-module/system/cart', ['require', 'exports', 'module'], function(require, exports, module) {

  exports.hello = function () {
      return "hello";
  };

});

amd-module/system/config.js

1
2
3
4
5
6
7
define('amd-module/system/config', ['require', 'exports', 'module'], function (require, exports, module) {

    exports.serverip = function () {
        return "127.0.0.1";
    };

});

代码

https://github.com/hans007/JavaScriptCodes/tree/master/fis3/use-amd

我的博客

Read More

前言

这是一个非常酷的功能,再也不用担心发布后资源目录需要调整。

在html中定位资源

1
src
1
href
属性就行处理

编译前

1
2
3
<img title="fis3 logo" src="logo.png"/>
<link rel="stylesheet" type="text/css" href="demo.css">
<script type="text/javascript" src="demo.js"></script>

在js中定位资源

使用编译函数

1
__uri(path)
来定位资源

编译前

1
2
3
4
5
<script>
var img = __uri('logo.png');
var css = __uri('demo.css');
var js = __uri('demo.js');
</script>

在css中定位资源

1
url(path)
以及
1
src=path
字段

1
2
3
4
5
6
7
8
9
<style>
@import url('demo.css');
.style {
    background: url('logo.png');
}
.style {
    _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='logo.png');
}
</style>

fis.match 匹配查询设置

比如匹配所有的文件进行hash文件名处理

1
2
3
fis.match('*', {
    useHash: true
});

API格式 fis.match(selector, props); selector 查询条件 props 配置详细

参考文 Glob 说明 , http://fis.baidu.com/fis3/docs/api/config-glob.html 更多属性 , http://fis.baidu.com/fis3/docs/api/config-props.html#%25E5%259F%25BA%25E6%259C%25AC%25E5%25B1%259E%25E6%2580%25A7

glob 规则

操作符

1
*
匹配0或多个除了
1
/
以外的字符
1
?
匹配单个除了
1
/
以外的字符
1
**
匹配多个字符包括
1
/
1
{}
可以让多个规则用 , 逗号分隔,起到或者的作用
1
!
出现在规则的开头,表示取反。即匹配不命中后面规则的文件

起始位置

fis-conf.js 所在目录

条件分组 $0 $1 $2

查询条件

1
2
3
fis.match('/a/({b,c}/**.js)', {
  release: '/static/$1$2'
});

$0 指整个条件 /a/ $1 指第一个子查询 (b/.js) $2 指第二个子查询 (c/.js)

启用hash方式

1
2
3
fis.match('*.{js,css,png,gif}', {
    useHash: true // 开启 md5 戳
});

useHash 属性 , 文件是否携带 md5 戳

设置发布文件目录

1
2
3
4
5
6
7
8
9
fis.match('**.js', {
    release : '/static/js/$0'
});
fis.match('**.css', {
    release : '/static/css/$0'
});
fis.match('**.png', {
    release : '/static/png/$0'
});

release 属性, 设置文件的产出路径

调整url

1
2
3
fis.match('**.js', {
    url : '/mm/static/js$0'
});

url 属性 , 指定文件的资源定位路径 默认是 release 的值,url可以与发布路径 release 不一致。

设置domain

1
2
3
fis.match('**.png', {
    domain: 'http://cdn.baidu.com/'
});

domain 属性 , 给文件 URL 设置 domain 信息 如果需要给某些资源添加 cdn,分配到此属性的资源 url 会被添加 domain;

运行并查看结果

源 uri.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在html中定位资源
<img title="fis3 logo" src="http://cdn.baidu.com/png_8652a39.png"/>
<link rel="stylesheet" type="text/css" href="/static/css/demo_3a5495f.css">
<script type="text/javascript" src="/static/js/demo_9b4f5bd.js"></script>

在js中定位资源
<script>
var img = 'http://cdn.baidu.com/png_8652a39.png';
var css = '/static/css/demo_3a5495f.css';
var js = '/static/js/demo_9b4f5bd.js';
</script>

在css中定位资源
<style>
@import url('/static/css/demo_3a5495f.css');
.style {
    background: url('http://cdn.baidu.com/png_8652a39.png');
}
.style {
    _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://cdn.baidu.com/png_8652a39.png');
}
</style>

配置 fis-conf.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fis.match('*.{js,css,png,gif}', {
    useHash: true // 开启 md5 戳
});

fis.match('**.js', {
    release : '/static/js/$0'
});
fis.match('**.css', {
    release : '/static/css/$0'
});
fis.match('**.(png)', {
    release : '/static/png/$1',
    url : '$1',
    domain: 'http://cdn.baidu.com/'
});

运行 fis3 release

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在html中定位资源
<img title="fis3 logo" src="http://cdn.baidu.com/png_8652a39.png"/>
<link rel="stylesheet" type="text/css" href="/static/css/demo_3a5495f.css">
<script type="text/javascript" src="/static/js/demo_9b4f5bd.js"></script>

在js中定位资源
<script>
var img = 'http://cdn.baidu.com/png_8652a39.png';
var css = '/static/css/demo_3a5495f.css';
var js = '/static/js/demo_9b4f5bd.js';
</script>

在css中定位资源
<style>
@import url('/static/css/demo_3a5495f.css');
.style {
    background: url('http://cdn.baidu.com/png_8652a39.png');
}
.style {
    _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://cdn.baidu.com/png_8652a39.png');
}
</style>

fis/www/ 目录

fis3-uri

资源文件路径不要跨过fis-conf.js的根目录

代码

https://github.com/hans007/JavaScriptCodes/tree/master/fis3/uri

我的博客

Read More

前言

为了减少请求数量,嵌入资源到 html、js、css 文件中。

嵌入到html中

采用资源链接加

1
?__inline
的方式

html中嵌入图片base64

1
<img title="fis3 logo" src="logo.gif?__inline"/>

html中嵌入样式文件

1
<link rel="stylesheet" type="text/css" href="demo.css?__inline">

html中嵌入脚本资源

1
<script type="text/javascript" src="demo.js?__inline"></script>

html中嵌入页面文件

1
<link rel="import" href="demo.html?__inline">

嵌入到js中

在js中,使用编译函数 __inline() 来提供内容嵌入能力。

在js中嵌入js文件

1
__inline('demo.js');

在js中嵌入图片base64

1
var img = __inline('logo.gif');

在js中嵌入其他文本文件

1
var css = __inline('a.css');

嵌入到css中

与html类似,添加

1
?__inline

在css文件中嵌入其他css文件

1
@import url('demo.css?__inline');

在css中嵌入图片的base64

1
2
3
.style {
      background: url(logo.gif?__inline);
  }

代码

https://github.com/hans007/JavaScriptCodes/tree/master/fis3/inline

我的博客

Read More

前言

fis是百度的前端自动构建工具,是一套前后端分离的自动化工具包。

和其它自动构建比起来,更强的地方还是在与后端的整合(PHP Smarty 、Laravel、http://oak.baidu.com/fis-plus、)。

fis首页 http://fis.baidu.com/

纯前端方案 https://github.com/fex-team/fis-pure

PHP后端方案 http://oak.baidu.com/fis-plus

JAVA后端方案 https://github.com/fex-team/jello

Go后端方案 https://github.com/xiangshouding/gois

Node后端方案 http://fex.baidu.com/yog2/

WEB前端研发部的门户网站有很多不错的文章 http://fex.baidu.com/

安装

需要

1
Node.js
1
NPM
环境

https://nodejs.org

新安装 FIS3

1
npm install -g fis3

更新 FIS3

1
npm update -g fis3

检查安装

输入

1
fis3 -v

正常输出

1
2
3
4
5
6
7
8
9
10
11
12
13
 [INFO] Currently running fis3 (/usr/local/lib/node_modules/fis3/)

  v3.4.25

   /\\\\\\\\\\\\\\\  /\\\\\\\\\\\     /\\\\\\\\\\\
   \/\\\///////////  \/////\\\///    /\\\/////////\\\
    \/\\\                 \/\\\      \//\\\      \///
     \/\\\\\\\\\\\         \/\\\       \////\\\
      \/\\\///////          \/\\\          \////\\\
       \/\\\                 \/\\\             \////\\\
        \/\\\                 \/\\\      /\\\      \//\\\
         \/\\\              /\\\\\\\\\\\ \///\\\\\\\\\\\/
          \///              \///////////    \///////////

macos 下需要 sudo 安装遇到问题可以参考 https://github.com/fex-team/fis/issues/565

查看命令功能

输入

1
fis3

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 [INFO] Currently running fis3 (/usr/local/lib/node_modules/fis3/)

 Usage: fis3 <command>

 Commands:

   init                           scaffold with specifed template.
   install                        install components
   release [media name]           build and deploy your project
   server <command> [options]     launch a server
   inspect [media name]           inspect the result of fis.match

 Options:

   -h, --help                print this help message
   -v, --version             print product version and exit
   -r, --root <path>         specify project root
   -f, --file <filename>     specify the file path of `fis-conf.js`
   --no-color                disable colored output
   --verbose                 enable verbose mode

最核心的只有3个命令

install 安装插件 release 发布生成文件 server 本地运行服务器

运行第一个程序
1
hello word!

fis3设计的伸缩性很强,毕竟这是第三个版本了,很优秀,后面我们会慢慢研究,先来跑一个

1
hello word!

下载官方demo

首先git下载fis3

1
git clone https://github.com/fex-team/fis3.git

生成文件到指定目录

  • 进入demo目录
1
cd fis3/doc/demo/demo-simple/

  • 运行生成
1
fis3 release -d ../dist

-d 参数是指输出到指定目录

  • 输出
1
2
3
[INFO] Currently running fis3 (/usr/local/lib/node_modules/fis3/)

 Ω ........ 261ms

可以看到disc目录成功生成

  • 变化1:资源位置发生变化

  • 变化2:CSS引用图片被合并

查看
1
fis-conf.js
文件

1
fis-conf.js
这个是fis的核心配置文件,我们来阅读下,我加入了注释。

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
// 载入csssprites合并插件,这个插件已经安装的时候内置
fis.match('::packager', {
  spriter: fis.plugin('csssprites')
});

// 所以的资源文件取消hash方式,你可以动手打开true看看
fis.match('*', {
  useHash: false
});

// 找到js文件,并启用js压缩
fis.match('*.js', {
  optimizer: fis.plugin('uglify-js')
});

// 找到css文件并启用合并
fis.match('*.css', {
  useSprite: true,
  //optimizer: fis.plugin('clean-css')
});

// 找到png文件并按标准压缩图片
fis.match('*.png', {
  optimizer: fis.plugin('png-compressor')
});
  • 大家可以试着修改些参数然后重新运行看看效果

输入

1
fis3 release -d dist

运行前请先删除 dist 目录

查看本地server目录

输入

1
fis3 server open

输出

1
2
3
 [INFO] Currently running fis3 (/usr/local/lib/node_modules/fis3/)

 [INFO] Browse /Users/hans/.fis3-tmp/www

会打开

1
www
所以在的资源管理器窗口

fis3-server-open

发布到server的
1
www
目录

输入

1
fis3 release

默认输出到server的

1
www
目录

fis3-release

运行本地server服务

输入

1
fis3 server start

输出

1
2
3
4
5
6
7
 [INFO] Currently running fis3 (/usr/local/lib/node_modules/fis3/)

 Starting fis-server .. at port [8080]

 [INFO] Browse http://127.0.0.1:8080/

 [INFO] Or browse http://169.254.189.89:8080/

fis3-server-start

关闭本地server服务

输入

1
fis3 server stop

输出

1
2
3
 [INFO] Currently running fis3 (/usr/local/lib/node_modules/fis3/)

 [INFO] Shutdown with pid [2341]

实时更新开发模式

输入

1
fis3 release -wL

输出

1
2
3
4
5
 [INFO] Currently running fis3 (/usr/local/lib/node_modules/fis3/)

 Ω ... 60ms
 Ψ 8132
 [14:45:52.905]

修改内容后浏览器自动刷新

我的博客

Read More

前言 - Grunt 到底是啥?

grunt

工作中我们会遇到,对代码(js,css,html)就行加工:压缩、合并、代码检查、测试 等等。

我们需要一个集成的环境 就行操作,Grunt就是这样的工具。

是一个js开发框架,具体功能是以安装插件的形式实现的,所以扩展性无限。


安装

安装 node.js

Grunt是基于Node.js为基础的,所以没装node.js的需要安装下。

http://nodejs.org/

已经安装的可以更新下

1
npm update -g npm

macos 下加 sudo

安装 Grunt CLI

1
npm install -g grunt-cli

配置我们第一个项目

建立项目目录

1
2
3
4
/grunt-do
   src/
   css/
   dist/

src 开发的js代码 css 开发的css代码 dist 发布代码

根目录下创建
1
package.json

1
2
3
4
5
6
{
  "name": "myapp",
  "version": "0.1.1",
  "devDependencies": {
  }
}

安装Grunt

1
npm install grunt --save-dev

package.json

1
devDependencies
被加入了依赖配置

1
2
3
4
5
6
7
{
  "name": "myapp",
  "version": "0.1.1",
  "devDependencies": {
    "grunt": "^1.0.1"
  }
}

多了个

1
node_modules
的目录,有空可以阅读下,暂时我们无视这个目录。

根目录下创建
1
Gruntfile.js

1
2
3
4
5
6
7
module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json')
    });

};

这是Grunt的配置文件 initConfig初始pkg属性,这都是套路,读取上面的package.json

插件

上面我们完成了项目的初始,具体的工作grunt都是以插件的形式实现的。

合并代码

  • 编写1个js文件

src/mods/module1.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 模块1
define(function(require, exports, module) {

    console.log("module1 被装载~");

    exports.num = 10;

    exports.add = function(){
        this.num ++;
    };

    exports.get = function(){
        return this.num;
    };

});

src/mods/module2.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 模块2
define(function(require, exports, module) {

    console.log("module2 被装载~");

    exports.num = 10;

    exports.add = function(){
        this.num ++;
    };

    exports.get = function(){
        return this.num;
    };

});
  • 安装插件

命令行

1
npm install grunt-contrib-concat --save-dev
  • 编写 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
module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        // 合并
        concat:{
            options:{
                separator:'\n',
                banner:'//model合并 \n',
                footer:'\n//--- end ---',
            },
            myapp:{
                src:['src/mods/*.js'],
                dest:'dist/<%= pkg.version %>/module.js'
            }
        },
    });

    grunt.loadNpmTasks('grunt-contrib-concat');

    grunt.registerTask('test', ['concat']);
};

concat.options 配置 separator 合并文件之间的字符 banner 头部字符 footer 底部字符

myapp 是你自己取的名字 可以多开 src 源文件 dest 目标文件

  • 运行&输出

命令行

1
grunt test

查看合并后的文件 dist/<版本号>/module.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
//model合并 
// 模块1
define(function(require, exports, module) {

    console.log("module1 被装载~");

    exports.num = 10;

    exports.add = function(){
        this.num ++;
    };

    exports.get = function(){
        return this.num;
    };

});
// 模块2
define(function(require, exports, module) {

    console.log("module2 被装载~");

    exports.num = 10;

    exports.add = function(){
        this.num ++;
    };

    exports.get = function(){
        return this.num;
    };

});
//--- end ---

压缩js代码

  • 安装插件

命令行

1
npm install grunt-contrib-uglify --save-dev
  • 编写 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
module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        // 合并
        concat:{
            options:{
                separator:'\n',
                banner:'//model合并 \n',
                footer:'\n//--- end ---',
            },
            myapp:{
                src:['src/mods/*.js'],
                dest:'dist/<%= pkg.version %>/module.js'
            }
        },

        // js压缩
        uglify:{
            module_targer:{
                options:{
                    banner:'/*app:<%= pkg.name %> , module all*/\n',
                    footer:'\n//--- end ---',
                },
                files:{
                    'dist/<%= pkg.version %>/module.min.js':['<%= concat.myapp.dest %>']
                }
            }
        },
    });

    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');

    grunt.registerTask('test', ['concat','uglify']);
};

files 的源文件是上次合并的dest内容,压缩后结果文件 module.min.js grunt.registerTask 任务是一个序列 先合并 后压缩 只要有一个环节出错 任务中断

  • 运行&输出

命令行

1
grunt test

查看 dist/<版本号>/module.min.js

1
2
3
/*app:myapp , module all*/
define(function(a,b,c){console.log("module1 被装载~"),b.num=10,b.add=function(){this.num++},b.get=function(){return this.num}}),define(function(a,b,c){console.log("module2 被装载~"),b.num=10,b.add=function(){this.num++},b.get=function(){return this.num}});
//--- end ---

压缩成功!


压缩css代码

  • 新建css文件

css/index.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.main {
	margin: 10px 0
}


/*多方适用*/

.bread,
.selector,
.type-wrap,
.value {
	overflow: hidden
}

.bread,
.selector,
.details,
.hot-sale {
	margin: 15px 0
}

......

  • 安装插件

命令行

1
npm install grunt-contrib-cssmin --save-dev
  • 编写 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
44
45
46
47
module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        // 合并
        concat:{
            options:{
                separator:'\n',
                banner:'//model合并 \n',
                footer:'\n//--- end ---',
            },
            myapp:{
                src:['src/mods/*.js'],
                dest:'dist/<%= pkg.version %>/module.js'
            }
        },

        // js压缩
        uglify:{
            module_targer:{
                options:{
                    banner:'/*app:<%= pkg.name %> , module all*/\n',
                    footer:'\n//--- end ---',
                },
                files:{
                    'dist/<%= pkg.version %>/module.min.js':['<%= concat.myapp.dest %>']
                }
            }
        },

        // css压缩
        cssmin:{
            index:{
                files:{
                    'dist/<%= pkg.version %>/index.min.css':['css/index.css']
                }
            }
        },
    });

    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-cssmin');

    grunt.registerTask('test', ['concat','uglify','cssmin']);
};

加入cssmin任务

  • 运行&输出

命令行

1
grunt test

查看 dist/<版本号>/index.min.css

1
.main{margin:10px 0}.bread,.selector,.type-wrap,.value{overflow:hidden}.bread,.details,.hot-sale,.selector{margin:15px 0}.filter,.hot-sale,.selector{border:1px solid #ddd}.key{padding:10px 10px 0 15px}.type-wrap ul li{float:left;list-style-type:none}.sui-btn{border-radius:0}.bread .sui-breadcrumb{padding:3px 15px;margin:0}

代码检查

  • 编辑js文件

src/mods/module1.js

1
2
3
4
// 模块1
define(function(require, exports, module) {
>>> haha
    console.log("module1 被装载~");

第三行加入错误

  • 安装插件

命令行

1
npm install grunt-contrib-jshint --save-dev
  • 编写 Gruntfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        // 检查js
        // http://jshint.com/docs/options/
        jshint:{
            files:['src/**/*.js'],
            // options:{
            //     jQuery:true,
            //     console:true,
            //     module:true,
            //     document:true
            // }
        },
    });

    grunt.loadNpmTasks('grunt-contrib-jshint');

    grunt.registerTask('jshint', ['jshint']);
};
  • 运行&输出

命令行

1
grunt jshint

grunt-jshint


代码测试

  • 编写测试

test/unit1.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>QUnit Example</title>
  <link rel="stylesheet" href="../lib/qunit.css">
</head>
<body>
  <div id="qunit"></div>
  <div id="qunit-fixture"></div>
  <script src="../lib/qunit.js"></script>
  
  <script>
  QUnit.test( "hello test", function( assert ) {
    assert.ok( 1 == "1", "Passed!" );
    });
  </script>

</body>
</html>
  • 安装插件

命令行

1
npm install grunt-contrib-qunit --save-dev
  • 编写 Gruntfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        // 测试
        qunit: {
            all: ['test/**/*.html']
        },
    });

    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.registerTask('qunit', ['qunit']);
};
  • 运行&输出

命令行

1
grunt qunit

grunt-qunit

CMD模式代码发布

  • 编写模块依赖代码

src\call.js

1
2
3
4
5
6
7
// 模块call
define(["mods/module1","mods/module2"],function(require, exports, module) {

    var mod1 = require("module1");
    var mod2 = require("module2");

});
  • 安装插件

命令行

1
npm install grunt-cmd-transport --save-dev
  • 编写 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
module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        // 转换
        transport:{
            options: {
                debug:false,
                include:'all'
            },
            module:{
                files: [{
                    expand: true,
                    cwd: 'src',
                    src: ['**/*.js', '!*.min.js'],
                    dest: 'dist/<%= pkg.version %>',
                    ext: '.js'
                }]
            },
        },
    });


    grunt.loadNpmTasks('grunt-cmd-transport');

    grunt.registerTask('ts', ['transport']);
};
  • 运行&输出

命令行

1
grunt ts

查看 dist/<版本号>/

1
2
输出到目录
dist/

被标准格式化了,加入了cmd模块的id,后期可以方便合并文件.


配置git
1
.gitignore

过滤掉

1
node_modules
目录

1
node_modules/

拿到一个现有项目

  • 安装需要的包文件
1
npm install
  • 查看
    1
    
    Gruntfile.js
    1
    
    grunt.registerTask
    定义

执行

1
grunt
看看是否有错误

1
grunt

需要注意

  • 任务的名字不要用插件的缩写,否则会无法运行。
1
2
// 错误的写法
grunt.registerTask('transport', ['transport']);

其它名字还有 concat、uglify、cssmin、jshint、qunit、transport …

  • 任务名字
    1
    
    default
    指默认任务
1
grunt.registerTask('default', ['concat','uglify','cssmin']);

运行

1
grunt

资料

http://gruntjs.com/ http://www.gruntjs.net/ http://jshint.com/docs/options/

代码

https://github.com/hans007/JavaScriptCodes/tree/master/gruntjs

我的博客

Read More

前言 - 什么是 CMD 模式

CMD是

1
Common Module Definition
的缩写,意思就是
1
通用模块加载规范

CMD 模式的 需要载入

1
Sea.js
这个包, 浏览器兼容ie5.5+ 所以放心用吧。

下载地址 http://seajs.org/

模块定义方式:

1
2
3
define("ID",["依赖模块"],function (require, exports, module) {

});

ID 当前模块的唯一 [“…”] 依赖模块 require 用来载入其它模块 exports 导出方法 module 导出模块

简单模块调用

  • 定义一个模块 module1.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 单例模式
define(function(require, exports, module) {

    console.log("module1 被装载~");

    exports.num = 10;

    exports.add = function(){
        this.num ++;
    };

    exports.get = function(){
        return this.num;
    };

});

通过 exports 导出了2个方法 add get,一个属性 num。 方法中访问成员变量 this.num 方式。

  • 建立调用页面 1-seajs模块调用.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script src="../sea-modules/core/sea.js" id="seajsnode" ></script>
<script>
    seajs.config({
        base: "../sea-modules/",
    });

    seajs.use(['lib/module1'],function(mod1){
        mod1.add();
        mod1.add();
        console.log(mod1.get());
    });

    seajs.use(['lib/module1'],function(mod1){
        mod1.add();
        mod1.add();
        console.log(mod1.get());
    });
</script>

导入sea.js包 定义seajs.config 的 base 代码根目录 seajs.use方式 使用 module1 连续调用了两次

  • 输出

module1 被装载~ 12 14

我们可以发现这是单例模式,作用域是整个页面,所以num是累加了。

非单例模式

  • 定义模块
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) {

    console.log("module2 被装载~");

    function UserModel() {

        var num = 1000;
        var name = "AAAAA";
        var uid = "1001";

        this.add = function () {
            num ++;
        };
        this.show = function () {
            return num + ":" + name + ":" + uid;
        };
    }

    module.exports = function () {
        return new UserModel();
    };
});

模型方式导出 module.exports

  • 定义入口 2-seajs非单例模块.html
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
<script src="../sea-modules/core/sea.js" id="seajsnode" ></script>
<script>
    seajs.config({
        base: "../sea-modules/",
    });

    seajs.use(['lib/module2'],function(mod2){

        var mod = new mod2();
        mod.add();
        mod.add();
        mod.add();

        console.log(mod.show());
    });

    seajs.use(['lib/module2'],function(mod2){

        var mod = new mod2();
        mod.add();
        mod.add();
        mod.add();

        console.log(mod.show());
    });
</script>

seajs.use 调用后 是一个 function() 我们用 new 的方式实例一个新对象 这里也是重复调用两次

  • 输出

module2 被装载~ 1003:AAAAA:1001 1003:AAAAA:1001

可以发现这次是非单例了,每次都是新的对象,互不影响。

模块依赖

  • 定义模块
1
2
3
4
5
6
7
8
9
10
// 模块依赖
define(['module1'],function(require, exports, module) {

    console.log("module3 被装载~");

    var mod1 = require('module1');
    mod1.add();

    console.log("module1 执行完成");
});

依赖模块 module1 require装载 module1 ,并执行 add 操作

  • 定义入口 3-seajs模块依赖.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script src="../sea-modules/core/sea.js" id="seajsnode" ></script>
<script>
    seajs.config({
        base: "../sea-modules/",
        alias: {
            "module1": "lib/module1.js"
        }
    });

    seajs.use(['lib/module3'],function(mod3){

        console.log("module3 执行完成");
    });
</script>

seajs.config alias 设置别名 module1

  • 输出

module3 被装载~ module1 被装载~ module1 执行完成 module3 执行完成

可以发现 CMD 果然是顺序执行,模块是懒加载,在需要的时候加载,不会像AMD方式先加载模块。 下载操作,是在执行定义依赖

1
define(['module1'],...
时浏览器客户端开始下载。

异步方式加载

1
2
3
4
5
6
7
define(function(require) {

  require.async('module1', function(mod1) {
    mod1.add();
  });

});

1
require.async
异步加载一个模块,在加载完成时,执行回调

模块化第三方代码 jquery

规范了模块的定义虽然好,但是用第三非CMD定义模块时,就有点麻烦了,比如这个jquery,你直接 require 直接返回

1
null

  • 修改
    1
    
    jquery
    的代码
1
2
3
4
5
6
7
8
define(function () {

    // jquery代码
    ...
    
    // 加入return
    return $.noConflict();
});

用一个

1
define
包裹下 最后
1
return $.noConflict();

  • 定义模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
define("lib/module4", ["./module4-ui"], function(require) {
    var ui = require("./module4-ui");
    ui.setup();
});

define("lib/module4-ui", ["jquery"], function(require, exports, module) {

    var $ = require("jquery");

    exports.setup = function () {

        $("#myButton").click( function () {
            alert(123);
        });
    };
});

我把UI处理单独出来了,设置模块ID

1
define("lib/module4"
1
var $ = require("jquery");
方式载入jquery模块 测试一个按钮事件

  • 定义入口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script src="../sea-modules/core/sea.js" ></script>

<script>
    seajs.config({
        base: "../sea-modules/",
        alias: {
            "jquery": "core/jquery-3.1.1.seajs.min.js"
        }
    });

    seajs.use("lib/module4");
</script>

<button id="myButton">点击我</button>

1
alias
配置了别名 模块中可以直接使用 放置了一个按钮
1
button

  • 输出

seajs-jquery-cmd化

触发成功

模块化 调用jquery插件

同样你要用相关依赖jquery的插件,也需要修改相关代码。

我这里修改了一个确认对话框插件 artDialog

  • 修改插件主程序
    1
    
    dialog.js
1
2
3
4
5
6
7
8
9
10
define("lib/artDialog/dialog", ["jquery"], function (require, exports, module) {

    var jQuery = require("jquery");

    // 放置原来的插件代码

    module.exports = function (options, ok, cancel) {
        return new dialog(options, ok, cancel);
    };
});

首先包一个

1
define
定义 然后创建依赖需要的
1
var jQuery = require("jquery");
对象 最后导出定义模块定义
1
module.exports = function ... 

  • 修改上面的模块代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
define("lib/module4", ["./module4-ui"], function(require) {
    var ui = require("./module4-ui");
    ui.setup();
});

define("lib/module4-ui", ["jquery","dialog"], function(require, exports, module) {

    var $ = require("jquery");
    var dialog = require("dialog");

    exports.setup = function () {

        $("#myButton").click( function () {
 
            var d = dialog({
                title: '欢迎',
                content: '欢迎使用 artDialog 对话框组件!'
            });
            d.showModal();
        });
    };
});

读取调用

1
var dialog = require("dialog");

  • 修改上面的入口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script src="../sea-modules/core/sea.js" ></script>
<script src="../sea-modules/core/seajs-css.js" ></script>

<script>
    seajs.config({
        base: "../sea-modules/",
        alias: {
            "jquery": "core/jquery-3.1.1.seajs.min.js",
            "dialog": "lib/artDialog/dialog.js"
        }
    });

    seajs.use("lib/artDialog/ui-dialog.css");
    seajs.use("lib/module4");


</script>

<button id="myButton">点击我</button>

加入alias别名

1
dialog
这里用了一个
1
seajs-css
的插件动态读取了css 插件地址 https://github.com/seajs/seajs-css/blob/master/README.md

  • 输出

seajs-jquery-cmd化-插件

弹出成功!

参考代码

https://github.com/hans007/JavaScriptCodes/tree/master/seajs%E6%A8%A1%E5%9D%97%E5%8C%96/app

我的博客

Read More

前言 - 什么是 AMD 模式

AMD是

1
Asynchronous Module Definition
的缩写,意思就是
1
异步模块加载规范

AMD 模式的 需要载入

1
requirejs
这个包, 浏览器兼容ie6+ 所以放心用吧。

下载地址 http://requirejs.org/

使用方式:

1
2
3
4
require(['模块文件名称'], function (对象名){

    对象名.方法();
});

可以看到当require调用模块成功后,才会回调 function 这个函数。

模块调用 单例方式

  • 首先定义模块 module1.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 单例
define(function () {

    console.log('module1 被装载~');

    var num = 0;

    var add = function () {
        num++;
    };

    var get = function () {
        return num;
    };

    return{
        add : add,
        get : get
    };
});

define方式包裹一个 function。

  • 主界面html
1
<script src="../core/require.js" data-main="main1"></script>

页面中调入 require.js, 标签节点

1
data-main
表示主控制js文件。

  • 主控制 main1.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 第一次调用
require(['lib/module1'], function (mod1){

    mod1.add();
    mod1.add();
    console.log(mod1.get());
});

// 第二次调用
require(['lib/module1'], function (mod1){

    mod1.add();
    mod1.add();
    console.log(mod1.get());
});

为了看看 作用域 ,我这里 调用了两次。

  • 输出

module1 被装载~ 2 4

可以看出 模块被

1
装载
后,整个页面全局有效。

非单例方式

有的模块需要非单例,否则每次都是全局使用。

  • 首先定义模块 module2.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 () {

    console.log('module2 被装载~');

    function UserModel() {

        var num = 1000;
        var name = "AAAAA";
        var uid = "1001";

        this.add = function () {
            num ++;
        };
        this.show = function () {
            return num + ":" + name + ":" + uid;
        };
    }

    return function () {
        return new UserModel();
    };
});

我这里 嵌套了 function,然后 返回的时候 new 了一个返回。

  • 主界面html
1
<script src="../core/require.js" data-main="main2"></script>

这里主控制是 main2.js

  • 主控制 main2.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 第一次调用
require(['lib/module2'], function (mod2){

    var mod = mod2();
    mod.add();
    mod.add();
    mod.add();

    console.log(mod.show());
});

// 第二次调用
require(['lib/module2'], function (mod2){

    var mod = mod2();
    mod.add();
    mod.add();
    mod.add();

    console.log(mod.show());
});

这里,我还是调用了两次。

  • 输出

module2 被装载~ 1003:AAAAA:1001 1003:AAAAA:1001

可以看出 每次调用的都是

1
全新
的实例对象,互不干扰。

继承调用

  • 首先定义模块 module3.js
1
2
3
4
5
6
7
8
9
10
11
12
13
// 继承
define(['module1'],function (mod1) {

    console.log('module3 被装载~');

    mod1.show = function () {
        return "number:"+mod1.get();
    };

    return function () {
        return mod1;
    };
});

define([‘module1’] 第一个参数就是依赖的模块文件名。

对象被传入后,直接扩展,最后返回被修改的对象。

  • 主界面html
1
<script src="../core/require.js" data-main="main3"></script>

这里主控制是 main3.js。

  • 主控制 main3.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
// 配置
require.config({
    baseUrl: "lib/"
});

// 第一次调用
require(['module3'], function (mod3){

    mod3().add();
    mod3().add();
    mod3().add();

    console.log(mod3().show());
});

// 第一次调用
require(['module3'], function (mod3){

    mod3().add();
    mod3().add();
    mod3().add();

    console.log(mod3().show());
});

require.config 是配置项目。

baseUrl 指模块的默认路径。

这里,我还是调用了两次。

  • 输出

module1 被装载~ module3 被装载~ number:3 number:4

可以看出 当多模块依赖的时候,都是先装载完成模块后 再依次执行命令,很符合浏览器行为。

别名调用

  • 主界面html
1
<script src="../core/require.js" data-main="main4"></script>

这里主控制是 main4.js。

  • 主控制 main4.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 配置
require.config({
    paths: {
        "jquery" : "../core/jquery-3.1.1.min"
    }
});

// 第一次调用
require(['jquery'], function (jq){

    var obj1 = jq(document);
    console.log(obj1[0].charset);

    var obj2 = $(document);
    console.log(obj2[0].charset);
});

paths 指定文件路径。

require的时候直接用别名就行。

  • 输出

windows-1252 windows-1252

jquery被载入后 $ 符号 还是可以用的。

参考代码

https://github.com/hans007/JavaScriptCodes/tree/master/requirejs%E6%A8%A1%E5%9D%97%E5%8C%96

我的博客

Read More

前言 - 为什么要闭包

我高度概括几点吧

  1. 实现面向对象 类
  2. 代码便于阅读
  3. 代码之间不会互相污染
  4. 提高复用性

单例闭包

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 声明
var myobjectModel = new Object({
    num : 0,
    add : function() {
        myobjectModel.num ++;
    },
    get : function() {
        return myobjectModel.num;
    }
});

// 调用
myobjectModel.add();
myobjectModel.add();
myobjectModel.add();
var val = myobjectModel.get();

输出:

3

直接对象访问 无需 new , 特别适合功能对象函数

非单例闭包

代码:

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
// 声明
var myobjectModel = function () {
     var instance = new Object();
     instance.num = 0;

     instance.add = function () {
         instance.num ++;
     };

     instance.get = function () {
         return instance.num;
     };

     return instance;
};

// 调用
var my1 = new myobjectModel();
my1.add();
my1.add();
var val1 = my1.get();
log(val1);

var my2 = new myobjectModel();
my2.add();
my2.add();
var val2 = my2.get();
log(val2);

输出:

2 2

对象被new后,互不影响。 适合可复用组件封装。

如果想内部对象私有化

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 声明
var myobjectModel = function () {
     var instance = new Object();
     instance.num = 0;

     instance.add = function () {
         instance.num ++;
     };

     instance.get = function () {
         return instance.num;
     };

     return {
         add : instance.add,
         get : instance.get
     };
};

运行时:

闭包私有化

如果需要其它模块支持

代码:

1
2
3
4
5
var myModule = (function(mod){
    
    ...
    
})(otherModule);

对象作为

1
参数
传入

如果各种原因模块没有载入成功

代码:

1
2
3
4
5
var myModule = (function(mod){
    
    ...
    
})(otherModule || {});

默认一个

1
空对象
进去

参考代码

https://github.com/hans007/JavaScriptCodes/tree/master/JS%E9%97%AD%E5%8C%85

我的博客

Read More