前端模块化开发

一、模块化开发
1.命名冲突
  在实际工作中,相信大家都遇这样的问题:我自己测试好的代码和大家合并后怎么起冲突了?明明项目需要引入的包都引进来了怎么还报缺少包?……这些问题总结起来就是命名空间冲突及文件依赖加载顺序问题。举个最简单的例子来解释一下命名空间冲突问题,看下面这段代码:。
test.html

复制代码

复制代码 module1.js

/**

  • Created by user on 2016/5/14.
    */
    var module=function(){
    cosonle.log(‘I am module1.js’);
    }
    module2.js

/**

  • Created by user on 2016/5/14.
    */
    var module=function(){
    console.log(“I am module2.js”);
    }
    当运行test.html时结果输出:

显然是因为前两个JS文件里的函数名与html里面的一致而导致冲突,所以只会执行最后一个module()函数,在团队合作中你不会知道自己写的函数或变量等是否会与别人起冲突,为解决此类问题出现了参照于JAVA的命名空间如下:

test.html

复制代码

复制代码 module1.js

复制代码
/**

  • Created by user on 2016/5/14.
    */
    var module1={};
    module1.fn={};
    module1.fn.Utils={};
    module1.fn.Utils.module=function(){
    console.log(“I am module1.js”);
    }
    复制代码
    module2.js

复制代码
/**

  • Created by user on 2016/5/14.
    */
    var module2={};
    module2.fn={};
    module2.fn.Utils={};
    module2.fn.Utils.module=function(){
    console.log(“I am module2.js”);
    }
    复制代码
    此时再运行test.html便可以输入所有的module里的值了

但是,写那么长的命名空间只为了调用一个方法,有没有感觉有些啰嗦呢?此处我只是为了尽量还原实际项目开发过程中的问题而起了较长的命名空间名。将命名空间的概念在前端中发扬光大,首推 Yahoo! 的 YUI2 项目。下面是一段真实代码,来自 Yahoo! 的一个开源项目。

if (org.cometd.Utils.isString(response)) {
return org.cometd.JSON.fromJSON(response);
}
if (org.cometd.Utils.isArray(response)) {
return response;
}
作为前端业界的标杆,YUI 团队下定决心解决这一问题。在 YUI3 项目中,引入了一种新的命名空间机制。

YUI().use(‘node’, function (Y) {
// Node 模块已加载好
// 下面可以通过 Y 来调用
var foo = Y.one(’#foo’);
});
YUI3 通过沙箱机制,很好的解决了命名空间过长的问题。然而,也带来了新问题。

YUI().use(‘a’, ‘b’, function (Y) {
Y.foo();
// foo 方法究竟是模块 a 还是 b 提供的?
// 如果模块 a 和 b 都提供 foo 方法,如何避免冲突?
});
暂且先不公布怎么解决此类问题,再看下一个问题。

2.文件依赖
开发最基本的原则就是不要重复,当项目中有多处地方运用同一个功能时,我们就该想办法把它抽离出来做成util,当需要时直接调用它即可,但是如果你之后的代码依赖于util.js而你又忘了调用或者调用顺序出错,代码便报各种错误,举个最简单的例子,大家都知道Bootstrap依赖jquery,每次引入时都要将jquery放在Bootstrap前面,一两个类似于这样的依赖你或许还记得,但如果在庞大的项目中有许多这样的依赖关系,你还能清晰的记得吗?当项目越来越复杂,众多文件之间的依赖经常会让人抓狂。下面这些问题,我相信每天都在真实地发生着。

1.通用组更新了前端基础类库,却很难推动全站升级。

2.业务组想用某个新的通用组件,但发现无法简单通过几行代码搞定。

3.一个老产品要上新功能,最后评估只能基于老的类库继续开发。

4.公司整合业务,某两个产品线要合并。结果发现前端代码冲突。

5.……

以上很多问题都是因为文件依赖没有很好的管理起来。在前端页面里,大部分脚本的依赖目前依旧是通过人肉的方式保证。当团队比较小时,这不会有什么问题。当团队越来越大,公司业务越来越复杂后,依赖问题如果不解决,就会成为大问题。

二、什么是模块化开发
模块化开发使代码耦合度降低,模块化的意义在于最大化的设计重用,以最少的模块、零部件,更快速的满足更多的个性化需求。因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。但总不能随便写吧,总得有规范让大家遵守吧。

1.目前,模块化开发有:
1.服务器端规范:CommonJs—nodejs使用的规范,

2.浏览器端规范:AMD—RequireJS国外相对流行(官网)

CMD–SeaJS国内相对流行(官网)

2.SeaJS与RequireJS的对比:
a. 对于依赖的模块,AMD是提前执行,CMD是延后执行;

b. CMD推崇依赖就近,AMD推崇依赖前置;

c. AMD的API默认是一个当多个用,CMD的API严格区分,推崇职责单一。

三、怎么用模块化开发
直接看下面写的小型计算机器代码吧!

test_seajs.html(前提是得去下载sea.js包哦,我是直接用命令npm install seajs下载的。)

复制代码

Seajs体验 + - x ÷ 复制代码 calculator.js文件内容如下: 复制代码 /** * Created by user on 2016/5/14. */

// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {
// 此处是模块的私有空间
// 定义模块的私有成员
// 载入convertor.js模块
var convertor = require(’./convertor.js’);

function add(a, b) {
return convertor.convertToNumber(a) + convertor.convertToNumber(b);
}

function subtract(a, b) {
return convertor.convertToNumber(a) - convertor.convertToNumber(b);
}

function multiply(a, b) {
return convertor.convertToNumber(a) * convertor.convertToNumber(b);
}

function divide(a, b) {
return convertor.convertToNumber(a) / convertor.convertToNumber(b);
}
// 暴露模块的公共成员
exports.add = add;
exports.subtract = subtract;
exports.multiply = multiply;
exports.divide = divide;
});
复制代码
convertor.js内容如下:
复制代码
/**

  • 转换模块,导出成员:convertToNumber
    */
    define(function(require, exports, module) {
    // 公开一些转换逻辑
    exports.convertToNumber = function(input) {
    return parseFloat(input);
    }
    });
    复制代码
    运行结果:

总结:在test_seajs.html用seajs.use引入calculator.js文件,而在calcultor.js文件中又require了convertor.js文件,这样就不用关心每个js依赖关系啦,因为在其js内部就已经加载完成了。每引入一个js在其回调函数里执行其js的方法,从而解决了命名冲突问题。

四、seajs暴露接口
细心的同学或许已经发现我在上面的calculator.js中用exports.xx暴露了该JS文件中的方法,如果里面有许多许多的方法,用exports都列出来多麻烦啊,其实还可以用module.exports来暴露其接口。如下:

test-exports.html

复制代码

复制代码 person.js

复制代码
/**

  • Created by user on 2016/5/14.
    */

// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {

 function Person(name, age, gender) {
   this.name = name;
   this.age = age;
   this.gender = gender;
 }
 Person.prototype.sayHi = function() {
   console.log('hi! I\'m a Coder, my name is ' + this.name);
 };

 //exports.Person=Person;
module.exports=Person;

});
复制代码
此时问题又来了,如果它俩同时存在以谁为准呢?答案是以module.exports为准,因为exports是module.exports的快捷方式,指向的仍然是原来的地址。看代码:

复制代码

复制代码 person.js

// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {
module.exports={name:‘haoxiaoli’};
exports.name=‘hxl’;
});
结果:

最后,其实还有一个return也可以暴露接口。它们的优先级为:return>module.exports>exports,看案例:

person.js

// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {
module.exports={name:‘haoxiaoli’};
exports.name=‘hxl’;
return {name:‘hello world!’};
});
结果:

五、异步加载包
引入JS时难免会遇到需要异步加载文件的时候,此时require.async便可满足异步加载需求。如下demo

html文件

复制代码

<script>
    // 在Seajs中模块的引入需要相对路径完整写法
    seajs.use('./03-module1.js', function(e) {
        //console.log(e);
    });
复制代码 03-module1.js文件

复制代码
define(function(require,exports,module){
/console.log(‘module1-------start’);
//require必须执行完成后(./module2.js加载完成)才可以拿到返回值
var module2=require(’./03-module2.js’);//阻塞代码执行
//JS中阻塞现在会造成界面卡顿现象出现
console.log(‘module1--------end’);
/

//异步加载便不会出现卡顿现象
console.log('module1--------start');
require.async('./03-module2.js',function(module2){
    //等03-module2.js后再做的操作
});//此处不会阻塞代码执行
console.log('module1--------end');

})
复制代码
六、使用第三方依赖库
比如当用CMD规范引入jquery时肯定希望它只在该模块内有效,而不是全局有效。在JQ中有对AMD规范的使用,但由于CMD属于国内的规范,人家并没有对其进行适配,所以需要我们手动去改造代码。在JQ中对AMD规范适配的下面增加如下代码。

复制代码
if (typeof define === “function” && !define.amd) {
// 当前有define函数,并且不是AMD的情况
// jquery在新版本中如果使用AMD或CMD方式,不会去往全局挂载jquery对象
define(function() {
return jQuery.noConflict(true);
});
}
复制代码
这样再使用JQ时便做到此模块内可用了。

define(function(require,exports,module){
//用JQ做代表第三方库
var $=require(’./jquery.js’);
$(document.body).css(‘backgroundColor’,‘red’);
});
七、seajs配置
假如你项目中用到许多JS文件,或者引入的JS路径发生了变化,这样挨个去文件中修改有点不现实,所以可以把它们集中在某个页面进行统一管理文件路径,即config配置文件。如你在某个html文件中写:

复制代码

<script>
    seajs.config({
        alias:{
            //给引入的包起别名,并放入到配置中
            calc:'./05-calc.js'
        }
    });
    seajs.use('calc');

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • [ test.html

复制代码

复制代码 module1.js

/**

  • Created by user on 2016/5/14.
    */
    var module=function(){
    cosonle.log(‘I am module1.js’);
    }
    module2.js

/**

  • Created by user on 2016/5/14.
    */
    var module=function(){
    console.log(“I am module2.js”);
    }
    当运行test.html时结果输出:

显然是因为前两个JS文件里的函数名与html里面的一致而导致冲突,所以只会执行最后一个module()函数,在团队合作中你不会知道自己写的函数或变量等是否会与别人起冲突,为解决此类问题出现了参照于JAVA的命名空间如下:

test.html

复制代码

复制代码 module1.js

复制代码
/**

  • Created by user on 2016/5/14.
    */
    var module1={};
    module1.fn={};
    module1.fn.Utils={};
    module1.fn.Utils.module=function(){
    console.log(“I am module1.js”);
    }
    复制代码
    module2.js

复制代码
/**

  • Created by user on 2016/5/14.
    */
    var module2={};
    module2.fn={};
    module2.fn.Utils={};
    module2.fn.Utils.module=function(){
    console.log(“I am module2.js”);
    }
    复制代码
    此时再运行test.html便可以输入所有的module里的值了

但是,写那么长的命名空间只为了调用一个方法,有没有感觉有些啰嗦呢?此处我只是为了尽量还原实际项目开发过程中的问题而起了较长的命名空间名。将命名空间的概念在前端中发扬光大,首推 Yahoo! 的 YUI2 项目。下面是一段真实代码,来自 Yahoo! 的一个开源项目。

if (org.cometd.Utils.isString(response)) {
return org.cometd.JSON.fromJSON(response);
}
if (org.cometd.Utils.isArray(response)) {
return response;
}
作为前端业界的标杆,YUI 团队下定决心解决这一问题。在 YUI3 项目中,引入了一种新的命名空间机制。

YUI().use(‘node’, function (Y) {
// Node 模块已加载好
// 下面可以通过 Y 来调用
var foo = Y.one(’#foo’);
});
YUI3 通过沙箱机制,很好的解决了命名空间过长的问题。然而,也带来了新问题。

YUI().use(‘a’, ‘b’, function (Y) {
Y.foo();
// foo 方法究竟是模块 a 还是 b 提供的?
// 如果模块 a 和 b 都提供 foo 方法,如何避免冲突?
});
暂且先不公布怎么解决此类问题,再看下一个问题。

2.文件依赖
开发最基本的原则就是不要重复,当项目中有多处地方运用同一个功能时,我们就该想办法把它抽离出来做成util,当需要时直接调用它即可,但是如果你之后的代码依赖于util.js而你又忘了调用或者调用顺序出错,代码便报各种错误,举个最简单的例子,大家都知道Bootstrap依赖jquery,每次引入时都要将jquery放在Bootstrap前面,一两个类似于这样的依赖你或许还记得,但如果在庞大的项目中有许多这样的依赖关系,你还能清晰的记得吗?当项目越来越复杂,众多文件之间的依赖经常会让人抓狂。下面这些问题,我相信每天都在真实地发生着。

1.通用组更新了前端基础类库,却很难推动全站升级。

2.业务组想用某个新的通用组件,但发现无法简单通过几行代码搞定。

3.一个老产品要上新功能,最后评估只能基于老的类库继续开发。

4.公司整合业务,某两个产品线要合并。结果发现前端代码冲突。

5.……

以上很多问题都是因为文件依赖没有很好的管理起来。在前端页面里,大部分脚本的依赖目前依旧是通过人肉的方式保证。当团队比较小时,这不会有什么问题。当团队越来越大,公司业务越来越复杂后,依赖问题如果不解决,就会成为大问题。

二、什么是模块化开发
模块化开发使代码耦合度降低,模块化的意义在于最大化的设计重用,以最少的模块、零部件,更快速的满足更多的个性化需求。因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。但总不能随便写吧,总得有规范让大家遵守吧。

1.目前,模块化开发有:
1.服务器端规范:CommonJs—nodejs使用的规范,

2.浏览器端规范:AMD—RequireJS国外相对流行(官网)

CMD–SeaJS国内相对流行(官网)

2.SeaJS与RequireJS的对比:
a. 对于依赖的模块,AMD是提前执行,CMD是延后执行;

b. CMD推崇依赖就近,AMD推崇依赖前置;

c. AMD的API默认是一个当多个用,CMD的API严格区分,推崇职责单一。

三、怎么用模块化开发
直接看下面写的小型计算机器代码吧!

test_seajs.html(前提是得去下载sea.js包哦,我是直接用命令npm install seajs下载的。)

复制代码

Seajs体验

复制代码
calculator.js文件内容如下:
复制代码
/**

  • Created by user on 2016/5/14.
    */

// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {
// 此处是模块的私有空间
// 定义模块的私有成员
// 载入convertor.js模块
var convertor = require(’./convertor.js’);

function add(a, b) {
return convertor.convertToNumber(a) + convertor.convertToNumber(b);
}

function subtract(a, b) {
return convertor.convertToNumber(a) - convertor.convertToNumber(b);
}

function multiply(a, b) {
return convertor.convertToNumber(a) * convertor.convertToNumber(b);
}

function divide(a, b) {
return convertor.convertToNumber(a) / convertor.convertToNumber(b);
}
// 暴露模块的公共成员
exports.add = add;
exports.subtract = subtract;
exports.multiply = multiply;
exports.divide = divide;
});
复制代码
convertor.js内容如下:
复制代码
/**

  • 转换模块,导出成员:convertToNumber
    */
    define(function(require, exports, module) {
    // 公开一些转换逻辑
    exports.convertToNumber = function(input) {
    return parseFloat(input);
    }
    });
    复制代码
    运行结果:

总结:在test_seajs.html用seajs.use引入calculator.js文件,而在calcultor.js文件中又require了convertor.js文件,这样就不用关心每个js依赖关系啦,因为在其js内部就已经加载完成了。每引入一个js在其回调函数里执行其js的方法,从而解决了命名冲突问题。

四、seajs暴露接口
细心的同学或许已经发现我在上面的calculator.js中用exports.xx暴露了该JS文件中的方法,如果里面有许多许多的方法,用exports都列出来多麻烦啊,其实还可以用module.exports来暴露其接口。如下:

test-exports.html

复制代码

复制代码 person.js

复制代码
/**

  • Created by user on 2016/5/14.
    */

// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {

 function Person(name, age, gender) {
   this.name = name;
   this.age = age;
   this.gender = gender;
 }
 Person.prototype.sayHi = function() {
   console.log('hi! I\'m a Coder, my name is ' + this.name);
 };

 //exports.Person=Person;
module.exports=Person;

});
复制代码
此时问题又来了,如果它俩同时存在以谁为准呢?答案是以module.exports为准,因为exports是module.exports的快捷方式,指向的仍然是原来的地址。看代码:

复制代码

复制代码 person.js

// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {
module.exports={name:‘haoxiaoli’};
exports.name=‘hxl’;
});
结果:

最后,其实还有一个return也可以暴露接口。它们的优先级为:return>module.exports>exports,看案例:

person.js

// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {
module.exports={name:‘haoxiaoli’};
exports.name=‘hxl’;
return {name:‘hello world!’};
});
结果:

五、异步加载包
引入JS时难免会遇到需要异步加载文件的时候,此时require.async便可满足异步加载需求。如下demo

html文件

复制代码

<script>
    // 在Seajs中模块的引入需要相对路径完整写法
    seajs.use('./03-module1.js', function(e) {
        //console.log(e);
    });
复制代码 03-module1.js文件

复制代码
define(function(require,exports,module){
/console.log(‘module1-------start’);
//require必须执行完成后(./module2.js加载完成)才可以拿到返回值
var module2=require(’./03-module2.js’);//阻塞代码执行
//JS中阻塞现在会造成界面卡顿现象出现
console.log(‘module1--------end’);
/

//异步加载便不会出现卡顿现象
console.log('module1--------start');
require.async('./03-module2.js',function(module2){
    //等03-module2.js后再做的操作
});//此处不会阻塞代码执行
console.log('module1--------end');

})
复制代码
六、使用第三方依赖库
比如当用CMD规范引入jquery时肯定希望它只在该模块内有效,而不是全局有效。在JQ中有对AMD规范的使用,但由于CMD属于国内的规范,人家并没有对其进行适配,所以需要我们手动去改造代码。在JQ中对AMD规范适配的下面增加如下代码。

复制代码
if (typeof define === “function” && !define.amd) {
// 当前有define函数,并且不是AMD的情况
// jquery在新版本中如果使用AMD或CMD方式,不会去往全局挂载jquery对象
define(function() {
return jQuery.noConflict(true);
});
}
复制代码
这样再使用JQ时便做到此模块内可用了。

define(function(require,exports,module){
//用JQ做代表第三方库
var $=require(’./jquery.js’);
$(document.body).css(‘backgroundColor’,‘red’);
});
七、seajs配置
假如你项目中用到许多JS文件,或者引入的JS路径发生了变化,这样挨个去文件中修改有点不现实,所以可以把它们集中在某个页面进行统一管理文件路径,即config配置文件。如你在某个html文件中写:

复制代码

<script>
    seajs.config({
        alias:{
            //给引入的包起别名,并放入到配置中
            calc:'./05-calc.js'
        }
    });
    seajs.use('calc');

] 计划任务

  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。1

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. 注脚的解释 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值