vue的三个特点:
Ø Mvvm
Ø 组件化
Ø 模块化
模块化是指文件的组织,管理,使用的方式 。
代码的开发阶段:把一个大的文件,拆分成几个小文件,它们之间相互引用,依赖。
代码发布之后:把这些小文件打包成一个大文件webpack。
1.1. 为什么要用模块化开发
以下面代码为例:
这个index.html文件中一共引入了8个 js文件。
这样组织至少会有两个问题:
(1)全局变量污染
(2)文件之间相互依赖的问题:Balloon.js文件必须要依赖于myjquery.js(这是我们自己写一个库),因为balloon.js中产生随机数所用的函数GetR来自于myjquery.js的。
解决:
(1)全局变量污染的问题,我们可以通过立即执行的函数表达式来解决。
(2)我们之前组织代码的方式,就不能很方便地看出来,哪个文件依赖于哪个文件。就算我们事先知道A.js依赖于B.js(可能A.js中用了B.js中的方法),我们也没有办法在浏览器端保证:B.js会在A.js之前加载完成。
1.2. 模块化的发展
模块化的思想主要是从后端的程序中引入的。
php -- include ”header.php”
1.2.1. 理解css中的模块化
Css -- @import
在es6之前,它不支持在一个js中直接去引入另一个js文件。
Ø 原始方式 --- 无模块时代
Ø 萌芽时代 --- 闭包+自执行函数、命名空间、人肉方式、配置参数
Ø CommonJS规范 --- CommonJs社区制定了Modules/1.0规范
Ø AMD规范 --- 革新派,RequireJS
Ø CMD规范 --- 中间派,seajs
Ø es6模块化 --- 终极解决方案
1.3. 闭包+立即执行函数的方式
它只是解决了文件之间的相互依赖关系的描述:
你一看到这个iife就可以知道,当前的这个模块(js文件)是依赖于哪些模块(js文件)的。
zepto就是这样做的
1.4. CommonJS规范
CommonJS规范源于Modules/1.0,在node.js中率先实现了。
核心内容有如下几点:
Ø 使用require方法引入其他模块(js文件),执行的结果即为别的模块(js文件)暴漏出来的API。
Ø 模块通过变量module.exports导出API,exports只能是一个对象,暴漏的API须作为此对象的属性。
Ø 如果require函数引入的模块中也包含依赖,则依次加载这些依赖。
Ø 如果引入模块失败,那么require函数应该报一个异常。
1.4.1. 定义模块
1.4.1.1. 格式
module.exports={
键值对
}
1.4.2. 引入模块
Let obj = require(“模块名’)
require函数,会返回一个对象,返回的是在模块中使用module.exports导出的对象
1.4.2.1. 引入模块的格式
模块名的路径,有两种:
Ø 自定义模块:使用相对路径,以./或../开头 模块名后可以加.js,也可以不加;你不能直接写模块名,就算是两个文件在同一个目录下,也加./
Ø 第三方模块:只需要写上模块名即可。这里的第三方模块,其实就是使用npm来安装的那些模块。
例如,你安装了vue模块。则在node_modules下会多一个文件夹:
你要想使用vue模块,只需要:
1.4.3. 示例
1.4.3.1. 浏览器端 不支持
现在有一个简单的需求,有三个文件如下:
Ø Index.html:它引入index.js文件
Ø Index.js:它执行一些功能,但它要入unit.js
Ø Unit.js:它就是一个库,提供一些方法
如果你现在去打开index.html文件,则浏览器一定会报错:
因为commonjs规则在浏览器端不支持。
但,在node.js中是支持commonjs规则的,即,上面的index.js文件可以直接通过node去运行。
1.4.3.2. 在nodejs中是支持的
1.4.4. 用browserify工具,把代码编译打包一下,让浏览器也能用
先通过npm安装。
(1)建议先在根目录,创建好package.json文件。
(2)全局安装和本地安装都可以。
npm install browserify -g (在任何一个小黑窗下都可以使用browserify命令)
或者是
npm install browserify --save (只能在当前的目录下使用这个命令)
(3)运行browserify 命令去转码
格式:
Browserify 要转码的.js -o 转码之后的.js
示例:
这里的blunder.js会自动创建的。
如下:
(4)在html中引入这个blunder.js即可。(之前引的是index.js,它不能用)
效果如下:
1.4.5. 应用:对前面的打气球游戏的js代码进行模块化处理
1.4.5.1. 把之前的立即执行的函数表达式的写法,改成commonjs的定义模块
改成:
把
改成:
其它的js文件的写法都类似。
对game.js
1.4.5.2. 用browserify对game.js进行转码
在html中引入转码之后的文件即可。
commonjs主要是在服务器端使用,在浏览器端虽然可以用browserify进行转码,但,并没有体现出浏览器与服务器端的区别:
浏览器端的代码是异步的,而服务器端是同步的。在浏览器端,提出 amd规范。
1.5. amd 规范 require.js
Asynchronous Module Definition
"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
amd是一种规范。require.js实现了这种规范。
1.5.1. 代表产品:require.js
1.5.2. Require.js的使用
1.定义模块
2.在主文件中引用模块
3.html中引入require.js
1.5.2.1. requirejs 定义模块(不是入口文件)
define(['模块1',’'模块2'’],function(变量1,变量2){
return {
}
});
(1)这里的变量就是这个模块的别名。
(2)如果当前模块不依赖其它的模块,则不需要写第一个参数,第二个参数中的形参列表也不要。
(3)这里也是使用模块。
示例:
1.5.2.2. requirejs 定义入口文件
require([“模块1”,“模块2”],function(变量1,变量2){
//你的代码
});
示例
Index.js需要使用unit.js这个模块
1.5.2.3. 在html页面中引入requirejs并指定入口文件
<script src="js/require.js" data-main="js/main" ></script>
(1)data-main是指定的主入口的名字。类似于c语言中的main函数一样。
(2)可以省略.js后缀。
效果如下:
1.5.3. 应用 :用require.js去改写对前面的打气球游戏的js代码
部分代码如下:
1.6. cmd规范 sea.js
“Common Module Definition”的缩写,意思就是"通用模块定义"。
cmd是一种模块化规范。
CMD推崇依赖就近,延迟执行
sea.js是推动cmd规范的产物。
1.6.1. 代表产品sea.js
1.6.1.1. seajs 定义模块--不需要引用其它模块
define(function(require,exports,module){
//你的代码,函数,变量,对象
//导出模块有三种方式
exports.属性名=值。//方式一
module.exports.属性名=值。//方法二
return 对象//方法三
});
(1)define是seajs定义的全局函数
1.6.1.2. seajs 定义模块--需要引用其它模块
define(function(require,exports,module){
//你的代码,函数,变量,对象
Var obj = require(‘模块名’)
//导出模板有三种方式
exports.属性名=值。//方式一
module.exports.属性名=值。//方法二
return 对象//方法三
});
1.6.1.3. 主入口
<script >
seajs.use(["模块1",“模块2”],function(变量1,变量2){
});
1.6.1.4. html页面中引入sea.js,和入口文件
1.6.2. 应用 :用sea.js去改写对前面的打气球游戏的js代码
注意一下:sea.js文件最好是和你的模块放在同一级目录下。
1.7. 查看jquery的代码
1.8. es6模块化
Import:导入。在自己当前的模块去使用其它模块
Export:导出。在定义模块时,决定把哪些内容暴露出去:当别的模块去引入当前模块,别人会得到什么东西。
1.8.1. 示例
Ø Index.html:引入index.js
Ø Index.js:要去引用unit.js
Ø Unit.js
现在,直接打开浏览器去访问index.html会得到一个错误:
由于import是es6的语法。在浏览器中不支持的,但我们可以通过babel进行转码。
下面,就要开始去转下码。
1.8.1.1. babel转码
Ø 安装bable
npm install babel-cli -g
Ø 安装两个包
npm install babel-preset-es2015 babel-preset-stage-2 --save-dev
Ø 编写配置文件
.babelrc
{
"presets":["es2015","stage-2"]
}
运行转码命令:
现在我们的文件如下::
细节:
在index.es5.js中,我们引入的文件应该要从unit.js改成unit.es5.js
在index.html中,把index.js 改成 index.es5.js。结果还是报错:require不认识。
我们通过babel从es6 --> es5之后:
实际是es6规范 ---> common规范
Es6 | Es5 |
| |
| |
Es6规范 | commonjs规范 |
commonjs规范:它还是不能在浏览器工作。但它可以直接在nodejs中运行。
为了让代码能够在浏览器中运行,我们还需要对index.es5.js文件进行browserify处理。
1.8.1.2. browserify处理
对入口文件(这个它引用其它的模块)进行处理:
browserify会分析index.es5.js文件,找出这个文件中依赖了哪些其它的文件,把它的依赖文件全部装到一个文件中:bundle.js。
修改index.html文件,把bundle.js引入:
成功啦!!!
1.8.2. Export
你在定义模块时,你可以决定,当你的模板被其它模板引入时,你暴露出去的内容是什么。
1.8.2.1. 逐个导出
1.8.2.2. 批量导出
1.8.2.3. 别名导出
1.8.3. Import
格式:
Import {变量名1,变量名2.... } from “模块名”
1.8.3.1. 逐个导出和批理导出
对于上面unit模块,它的两种导出方式,我们都可以用如下的方式进行导入:
(1)导入时,你使用的变量名data,name必须要与unit模块中导出时用的名字要一致。
(2)两个变量之间先后顺序是没有的关系的(对象是属性的无序集合)
(3)上面的模块的路径的写法(”./unit”)与commonjs中的require的要求是一样的:
Ø 如果自己定义的模块,则一定要加 ./(表示当前目录) ../(上一级目录)
Ø 如果是第三方的模块,则直接写模块名。
如上代码说明,vue这个模块是默认导出的。
1.8.3.2. 别名导入
在导入数据时,取个别名。
1.8.4. Export default
在导出和导入我们需要保持属性名是一致,这就比较麻烦。
我们通过通过exprot default来把取名的工作交给引用模块:即我导出时,不取名字,你导入时,爱取什么名字就取什么名字。
1.8.4.1. 定义模块
1.8.4.2. 引入模块
1.8.4.3. Export default和批量导出可以一起用
导出模块
导入模块
1.8.5. 模块的整体加载
Import * as
模块还是正常地批量导出:
导入时
2. 模块化总结
模块化
Ø 一个js文件就是一个模块;
Ø 把很多个模块通过相互引用的方式组合在一起 ;
Ø 在index.html中,只引入一个模块
有四种规范
Ø Commonjs:在nodejs中支持的。在服务器端工作。
Ø Amd:在浏览器端工作 。代表产品是:require.js
Ø Cmd:在浏览器端工作 。代表产品是:sea.js
Ø ES6 :正宗。完全可以构建 服务器端 和浏览器 都支持的 方案。
方案名 | 定义模块 | 使用模块 | 主入口 |
|
commonjs | modules.exports={} | require() obj =require(‘./模块名’) |
| browserify转码
|
amd-seajs | defind(require,export,module) | defined(require,export,module){ require (./模块名)} | seajs.use([],functin(){ }) | sea.js
|
cmd-require | define(function(){return {} });
| define(['模块'],function(变量){return {} }); | require(["game"],function(g){})
data-main | common.js |
es6 | export | import |
| babel browserify |