1. 浏览器端的 AMD 和 CMD 模块化规范 (了解)
浏览器端,不能使用 Common.js 规范,因为 Common.js 是同步加载的;
AMD/CMD 可以理解为,common.js 在浏览器端,的解决方案,是异步加载的;
- AMD模块化规范代表:RequireJS框架
对于依赖的模块,AMD 是提前执行;
推崇依赖前置,先定义模块,再使用; - CMD模块化规范代表:SeaJS框架
对于依赖的模块,CMD 是延迟执行;
CMD 推崇,尽可能晚的,执行这个模块,类似懒加载;推崇依赖就近; - ES6模块化 (大趋势):ES6 在语言标准层面上(语法上),实现了模块化功能,而且实现得相当简单;完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器,通用的模块化解决方案;(vue Reat 前端框架会使用)
2. 模块成员的分类
Node.js 由三部分组成:ECMAScript 核心 + 全局成员 + 模块成员
模块成员,分三类: 核心模块、第三方模块、用户自定义模块
- 核心模块
随着Node.js的安装包,一同安装到,本地的模块;如:fs,path 等;
核心模块使用:require(‘核心模块标识符’) - 第三方模块
非官方提供的模块;必须去 NPM 网站上下载,才能使用;
先从 npm 官网上,下载指定的,第三方模块;
require(‘第三方模块标识符’) 导入模块;根据 第三方模块的 官方文档,尝试使用; - 用户自定义模块
程序员自己,写的 Javascript 文件;
使用:require(‘路径标识符’)
3. 包(Packages)的定义和使用
可看作是 模块、代码 和 其它资源 组合起来,形成的 独立作用域;是在模块的基础上,更深一步的抽象;
1) 规范的包结构
- 包都要以一个单独的目录而存在;目录名,必须是英文,不能是中文,或数字开头;
- package.json 必须在包的顶层目录下;
- package.json 文件必须符合 JSON 格式,并包含如下三个属性:
- name: 包的名字
- version: 包的版本号
- main: 包的入口文件
- 二进制文件,应该在bin目录下;
- javaScript 代码,应该在lib目录下;
- 文档应该在doc目录下;
- 单元测试,应该在 test目录下;
- README.md 包的 使用说明文档;
- Node.js 对包的要求,并不严格,只要顶层目录下,有 package.json,并符合基本规范即可;
2) 包描述文件 package.json
name:包的名称,必须是唯一
description:包的简要说明
version:符合语义化版本识别规范的版本字符串
keywords:关键字数据,通常用于搜索
maintainers:维护者数组,每个元素要包含name、email、web可选字段
contributors:贡献者数组,格式与maintainers相同
bugs:提交bug的地址,可以是网址或者电子邮件地址
licenses:许可证数组,每个元素要包含type和url字段
repositories:仓库托管地址数组,每个元素要包含type、url和path字段
dependencies:包的依赖,一个关联数组,由包名称和版本号组成
devDependencies:开发依赖项,表示一个包在开发期间用到的依赖项
calc计算器模块的解构
4.1 npm 的两层含义
- NPM:一个 第三方模块的,托管网站:https://www.npmjs.com/;
- NPM (Node package manager):Node 的包管理工具,安装 Node 时,就已顺便安装了;
4.2 安装和卸载全局包
-
全局包:安装到计算机全局环境中的包;可以安装在,任何目录下,直接通过命令行来访问;
-
安装全局包: npm install 包名 -g ; -g 安装到 全局目录中;
-
全局包安装目录:C:\Users\用户目录\AppData\Roaming\npm
工具性质的包,适合安装到全局; -
卸载全局包:npm uninstall 包名 -g;uninstall 卸载;
npm i i5ting_toc -g //要转换文件的文件夹 -> 终端 -> i5ting_toc -f .\node_day02.md
4.3 安装和卸载本地包
- 本地包:跟着项目安装的包;安装到 node_modules 目录下;
- 一个空项目,必须在当前项目,根目录中,先运行 npm init 或 npm init -y,初始化一个 package.json 配置文件,否则其它包,无法安装到本地项目中;
- 安装本地包:npm i 包名 --save ;
- package-lock.json 文件中,记录了曾经装过的,包的下载地址;
- 卸载本地包:npm uninstall/remove 包名 -S/-D ;
4.4 其它常用命令
- –save 缩写 -S;npm 5.x 版本,可以不指定 --save 命令;
- –save-dev 缩写 -D
- install 缩写 i
- dependencies 节点,表示项目上线部署时,需要的依赖项;
devDependencies节点,表示项目在开发阶段,需要的依赖项,当项目部署上线了,devDependencies节点中的包,就不需要了; - npm i --production 只安装 dependencies 节点下的包,不安装 devDependencies 节点下的包;npm i 会安装所有的包,当项目要上线时,删除文件夹,运行 npm i --production
发送自己的,项目文件给同事,先删除 node_modules文件夹,再发送;
收到文件后,右键–>打开终端窗口–>npm i;当使用 npm i 快速装包时,npm 会检查 package.json 文件中,所有的依赖项,然后都安装到项目中;
4.5 解决 npm 下载慢问题
- NPM 下载包时,连接的是,国外的服务器,网速不好,下载不了;
- 此时,全局安装一个 cnpm 工具: npm i cnpm -g
- 在装包时,只需把 npm 替换成 cnpm 即可;例如安装 jquery: cnpm i jquery -S
安装 nrm 设置淘宝镜像,解决下载慢问题
1. npm i nrm -g
2. nrm ls
3. nrm use taobao
npm config set registry https://registry.npm.taobao.org //设置淘宝镜像
5. 使用 Node 构建 web 应用
- PHP是后端,网站开发语言,PHP 开发出来的网站,可以通过 Apache 服务器托管,运行起来;
- Node中,有没有类似于 Apache,这样的服务器呢?没有,要自己写;
1) B/S 交互模型:特指 浏览器(Browser)和 服务器(Server) 这种交互形式;
HTTP 协议通信模型:请求 - 处理 - 响应 的过程;
- 请求:由客户端,发起请求;
- 处理:服务器端,处理请求;
- 响应:服务器端,把处理结果,发送给客户端;
静态资源:服务器端只需要读取,并直接发送给客户端,不需要进一步,处理的资源;
动态资源:服务器端没有现成的资源,需要服务器端,动态生成的资源;
2) 实现一个 类似于Apache的 静态资源服务器
- 使用 http核心模块 http.createServer() 方法,创建最基本的 web 服务器;
- 绑定监听事件 并指定 处理函数:
server.on(‘request’, function(req, res) { 请求的处理函数 }) - 启动服务器:
server.listen(端口, IP地址, 启动成功的回调函数)
// 1. 导入 http 核心模块
const http = require('http')
// 2. http.createServer 创建一个 web 服务器对象;此时,并不能监听任何 客户端请求,也没有启动;
const server = http.createServer()
// 3. 为 server服务器,绑定 监听函数,通过 on方法,绑定 request请求事件,监听 客户端的请求;
server.on('request', function (req, res) {
// reg 请求对象;res 响应对象
/* 防止中文乱码,需要写在res.end之前;
通过设置 响应报文头的 Content-Type,来指定,响应内容的编码类型,从而防止乱码;*/
res.writeHeader(200, {
'Content-Type': 'text/plain; charset=utf-8' //配置响应头
})
res.end('你好') //服务器返回中文,会有乱码问题;只要监听到有人请求服务器,就返回固定的内容:‘你好’;
})
// 4. server.listen 启动服务器
server.listen(3000, '127.0.0.1', function () {
console.log('server running at http://127.0.0.1:3000')
})
//防止中文乱码2
server.on('request', function(req, res) {
res.write('<head><meta charset="UTF-8"></head>')
res.end('你好')
})
3) 根据不同的 URL,返回不同的内容
- 使用 req.url 获取客户端,请求的URL地址;
- 根据请求的不同路径,返回不同的内容;
const http = require('http')
const server = http.createServer()
server.on('request', function (req, res) {
// console.log(req.url) -->客户端请求的 URL地址
const url = req.url
// 防止中文乱码
res.writeHeader(200, {
'Content-Type': 'text/plain; charset=utf-8'
})
if (url === '/' || url === '/index.html') { '/'根目录?
res.end('首页')
} else if (url === '/movie.html') {
res.end('电影')
} else if (url === '/about.html') {
res.end('关于')
} else {
res.end('请求内容不存在!')
}
})
server.listen(3000, function () {
console.log('server running at http://127.0.0.1:3000')
})
text/plain 和 text/html 的区别:
plain 表示普通的文本字符串; html 表示以 HTMl 标签的形式,去解析服务器的,返回内容;
// 防止中文乱码
res.writeHeader(200, {
'Content-Type': 'text/plain; charset=utf-8'
})
res.end('<h3>首页</h3>') //返回 <h3>首页</h3> ,不解析;
res.writeHeader(200, {
'Content-Type': 'text/html; charset=utf-8'
})
res.end('<h3>首页</h3>') //返回解析过的‘首页’
4) 根据不同的 URL,返回不同的 HTML页面
使用 fs模块 读取,URL 对应的 HTML,页面内容,并使用 res.end() 响应给客户端;
const fs = require('fs')
const path = require('path')
const http = require('http')
const server = http.createServer()
server.on('request', function (req, res) {
const url = req.url
if (url === '/' || url === '/index.html') {
//返回首页页面: 使用 fs模块,读取 首页文件;把读取到的首页,通过 res.end 返回即可;
//没有出现乱码,是因为 index.html中 <meta charset="UTF-8"> 防止了页面乱码;
fs.readFile(path.join(__dirname, './views/index.html'), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
} else if (url === '/movie.html') {
// 返回电影页面
fs.readFile(path.join(__dirname, './views/movie.html'), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
} else if (url === '/about.html') {
// 返回关于页面
fs.readFile(path.join(__dirname, './views/about.html'), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
}
})
server.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000')
})
//__dirname +'./views/movie.html' 不能加‘.’也不能少‘/’;path.join则无限制;
fs.readFile(path.join(__dirname, './views/about.html'), 'utf-8', (err, dataStr) => {
res.end(dataStr)
})
// 以 utf-8 形式的字符串读取;如果省略掉,读取的内容,变成二进制的格式;
// res.end() 方法,接收两种类型的数据 String,二进制;
// 如果是string,先把字符串->二进制,再通过网络发送出去,客户端接收后,再转成字符串,所以'utf-8'可以省略
5) 处理并返回 css样式,和 Javascript文件
- 如果客户端要拿到,页面引入的 css 或 js样式;必须在服务器端,监听这个请求地址;
- 客户端所请求的,任何文件或资源;服务器端,必须要监听,并响应之后,客户端才能拿到;
const fs = require('fs')
const path = require('path')
const http = require('http')
const server = http.createServer()
server.on('request', function (req, res) {
let url = req.url
if (url === '/css/1.css') {
// 读取样式表
fs.readFile(path.join(__dirname, '/css/1.css'), (err, buf) => {
if (err) return res.end('404. Not found.')
res.end(buf)
})
} else if (url === '/js/1.js') {
// 读取 JS 文件
fs.readFile(path.join(__dirname, '/css/1.js'), (err, buf) => {
if (err) return res.end('404. Not found.')
res.end(buf)
})
}
})
server.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000')
})
//项目最终优化
server.on('request', function (req, res) {
let url = req.url //url地址是改变的,所以不能用const
if (url === '/') url = '/views/index.html'
fs.readFile(path.join(__dirname, url), (err, buf) => {
if (err) return res.end('404. Not found.')
res.end(buf)
})
})
6) Node中 结合模板引擎 渲染动态页面
- art-template 模板引擎;同时支持 Node.js 和 浏览器;
- 安装模板引擎 npm init -y (项目名称 package name: test) npm i art-template
- 导入模板引擎:const template = require(‘art-template’)
const template = require('art-template')
const path = require('path')
const http = require('http')
const server = http.createServer()
server.on('request', function (req, res) {
const url = req.url
if (url === '/') {
// template('要渲染的 html页面路径',{要渲染的数据/没有要渲染的数据,指定一个空对象})
// template 方法的返回值,就是渲染好的 html页面,直接通过 res.end 发送给客户端
const htmlStr = template(path.join(__dirname, '/views/1.html'), { name: 'zs', age: 22, hobby: ['吃饭', '唱歌', '跳舞'] })
res.end(htmlStr)
}
})
server.listen(3000, function () {
console.log('server running at http://127.0.0.1:3000')
})
html 内容
<h1>Node 服务器,结合 art-template 模板引擎,渲染的动态页面</h1>
<p>姓名:{{name}}</p>
<p>年龄:{{age}}</p>
<p>
爱好:
{{each hobby}} //{{开始循环 each 数组名称}}
<span>{{$value}}</span> //{{$value 循环的每一项数据}}
{{/each}} // {{结束循环 /each}} 爱好:吃饭 唱歌 跳舞
</p>