1、node介绍和环境安装
1.1 为什么JavaScript可以浏览器中被执行
浏览器中有JavaScript解析引擎
不同的浏览器使用不同的JavaScript解析引擎
- chrome 浏览器 => V8
- Firefox 浏览器 => odinmonkey(奥丁猴)
- Safri 浏览器 => JScore
- IE 浏览器 => chakra (查克拉)
- etc
chrome 浏览器的 V8解析引擎性能最好
1.2 为什么JavaScript可以操作 DOM和BOM
每个浏览器都内置了 DOM api BOM api Ajax api ,通过JavaScript解析引擎执行。浏览器中的JavaScript才可以调用他们
1.3 浏览器中JavaScript的运行环境
运行环境是指代码正常运行所需的必要环境
chrome 浏览器运行环境:V8引擎、内置api,然后就可以写JavaScript代码,然后交给 V8引擎解析
- V8 迎亲负责解析和执行 JavaScript 代码
- 内置 API 是由运行环境提供的特殊接口,只能在所属的运行环境中被调用
1.4 JavaScript能否做后端开发
后端开发主要语言:Java python PHP
JavaScript可以借助node.js来做后端开发
1.5 什么是 node.js
node.js 是 一个基于 chrome V8 引擎 的JavaScript 运行环境
官网:https://node.js.org/zh-cn/
1.6 node.js 中 JavaScript运行环境
- node.js 中 无法调用 DOM 和BOM 、Ajax等浏览器内置 API
- 因为node中没有这些内置 API
1.7 node 可以做什么?
- 基于 Express 框架(http://www.expressjs.com.cn/),可以快速构建web应用
- 基于 Electron 框架(https://electronjs.org/),可以构建平台的桌面应用
- 基于 restify 框架 (http://restify.com/),可以快速构建api接口项目
- 读写和操作数据库,创建实用的命令行工具辅助前端开发 etc
总之:node.js 是大前端时代的 大宝剑,有了node.js 这个超级 buff 的加持,前端程序员的行业竞争力会越来越强
node.js 内置 api 模块
- fs
- path
- http
- etc……
第三方 api模板
- express
- mysql
- etc……
1.8 下载安装 node
LTS 和 Current 版本的不同
- LTS 为长期稳定版,对于 追求稳定性 和 企业级项目 来说, 推荐安装 LTS 版本的node.js
- Current 为新特性尝鲜版,对于热衷于尝试新特性的用户来说,推荐安装 Current 版本 的 node.js 。但是,current 版本中可能存在隐藏 的bug 或者 安全性漏洞,因此不推荐在企业级项目中使用 current 版本的 node.js
安装方法,一路 next 即可
1.9 查看已经安装的 node.js 的版本号
打开终端,在终端输入命令 node -v 后,按下回车键,即可
1.10 什么是终端
终端是专门为开发人员设计的,用于实现人机交互的一种方式
作为一名合格的程序员,我们有必要识记一些常用的终端命令,来辅助我们更好的操作与使用计算机
1.11 在node.js环境中执行JavaScript代码
- 打开终端
- 输入node 要执行的js文件路径
注意: cd 是切换目录
F:\>cd F:\黑马年度班2020.8.30\四阶段前后端交 互\第四章node.js\代码
F:\黑马年度班2020.8.30\四阶段前后端交互\第四 章node.js\代码>node 01.js
HEllo 你好
1.12使用更方便的形式 执行 node 命令
- 先打开文件所处的文件夹内
- 按住 shift 然后鼠标右击
- 选择:在此处打开 power shell 窗口
1.13 了解常用的终端快捷键
- ⬆ 可以快速定位到上一次执行的命令
- 使用 tab 键,可以快速补全文件的路径
- esc 键,能快速清空当前已经输入的命令
- 输入 cls 命令,可以清空当前终端 的内容
2、node-fs模块
2.1 了解什么是 fs 文件系统模块
fs 模块是 node.js 官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求
- fs.readFile() 方法,用来读取指定文件中的内容
- fs.writeFile() 方法,用来向指定的文件中写入内容
如果要在JavaScript代码中,使用 fs 模块来操作文件,则需要使用如下的方式导入它
const fs = require('fs')
// 使用 require 函数 来导入
// fs 输出后 是一个对象,包含很多东西
2.2 读取指定文件中的内容
fs.readFile() 的语法格式
fs.readFile(path[,options],callback)
- 参数1:必选参数,字符串,表示文件的路径。
- 参数2:可选参数,表示以什么编码格式来读取文件。
- 参数3:必选参数,文件读取完成后,通过回调函数拿到读取的结果
const fs = require('fs')
/* require就是一个引入函数,在此处引入的是fs模块 */
fs.readFile('./files/1.txt', 'utf8', function (err, dataStr) {
/*
第一个参数 是路径
第二个参数 是编码格式,一般默认指定utf8
第三个参数中的第一个形参是失败的结果
第三个参数中的第一个形参是成功的结果
*/
console.log(err);
console.log('-------');
console.log(dataStr);
// 如果读取成功则err的值为null,dataStr的值是文件的内容
// 如果读取失败则err的值为错误对象,dataStr的值是undefined
/*
结果为:
null
-------
111
*/
})
2.3 fs判断文件是否读取成功
const fs = require('fs')
/* require就是一个引入函数,在此处引入的是fs模块 */
fs.readFile('./files/11.txt', 'utf8', function (err, dataStr) {
if (err) {
return console.log("文件读取失败!" + err.message);
}
console.log('文件读读取成功,内容是:' + dataStr);
})
2.4 使用fs.writeFile方法写入文件
fs.writeFile(file,data[,options],callback)
// 参数1:必选参数,需要指定一个文件路径的字符串,表示文件存放路径
// 参数2:必选参数,表示要写入的内容
// 参数3:可选参数,表示以什么格式写入文件内容,默认值是utf8
// 参数4:必选参数,文件写入完成后的回调函数
// 1、导入 fs 文件系统模块
const fs = require('fs')
// 2、调用fs的writeFile方法
// 第一个参数是存放文件的路径,第二个是内容,第三个是回调函数
fs.writeFile('./files/2.txt', 'abcde', function (err) {
// 文件写入成功则err的值等于null
// 文件写入失败则err的值等于错误对象
console.log(err);
})
2.5 判断文件是否写入成功
// 1、导入 fs 文件系统模块
const fs = require('fs')
// 2、调用fs的writeFile方法
// 第一个参数是存放文件的路径,第二个是内容,第三个是回调函数
fs.writeFile('./files/2.txt', 'abcdefg', function (err) {
// 文件写入成功则err的值等于null
// 文件写入失败则err的值等于错误对象
if (err) {
return console.log('写入内容失败');
}
console.log('写入内容成功');
})
2.6 案例 需求、分析
数据没有整理前
小红=99 小李=100 呆呆=180 张三=59
数据整理后
小红:99
小李:100
呆呆:180
张三:59
- 导入需要的fs文件系统模板
- 读取旧文件的内容
- 判断是否成功
- 处理数据
- 写入到新的文件中去
2.7 读取成绩
2.8 处理成绩
const fs = require('fs')
fs.readFile('./files/成绩.txt', 'utf8', function (err, dataStr) {
if (err) {
return console.log('读取成绩失败!');
}
console.log('读取成绩成功!!!');
// 1、先按照空格,把这些数据分隔成数组
const dataOld = dataStr.split(' ')
// [ '小红=99', '小白=100', '小黄=70', '小黑=66', '小绿=88' ]
const arrNew = []
// forEach 循环遍历数组的每一项
dataOld.forEach((value) => {
arrNew.push(value.replace('=', ':'))
})
console.log(arrNew);
// 2、循环分隔后的数组,对每一项的数据进行字符串的替换操作
// '\r\n' 就表示回车换行
console.log(arrNew.join('\r\n'));
})
2.9 将整理好的数据写入到新文件
const fs = require('fs')
fs.readFile('./files/成绩.txt', 'utf8', function (err, dataStr) {
if (err) {
return console.log('读取成绩失败!');
}
console.log('读取成绩成功!!!');
// 1、先按照空格,把这些数据分隔成数组
const dataOld = dataStr.split(' ')
// [ '小红=99', '小白=100', '小黄=70', '小黑=66', '小绿=88' ]
const arrNew = []
// forEach 循环遍历数组的每一项
dataOld.forEach((value) => {
arrNew.push(value.replace('=', ':'))
})
console.log(arrNew);
// 2、循环分隔后的数组,对每一项的数据进行字符串的替换操作
// '\r\n' 就表示回车换行
const newStr = arrNew.join('\r\n')
console.log(arrNew.join('\r\n'));
fs.writeFile('./files/成绩-ok.txt', newStr, function (err) {
if (err) {
return console.log('写入文件失败');
}
console.log('写入文件成功');
})
})
2.10 演示路径动态拼接的问题
在使用fs模块操作文件时,如果提供的操作路径是以 ./ 或 …/ 开头的相对路径时,很容易出现路径动态拼接错误的问题
原因:代码在运行的时候,会以执行 node 命令时所处的目录,动态拼接出被操作文件的完整路径
出现问题是因为提供了 ./ …/ 开头的相对路径
想要解决这个问题,可以直接提供一个完整的文件存放路径就行
2.11 使用完整路径代替相对路径
// 1、导入 fs 文件系统模块
const fs = require('fs')
// 注意在js中一个斜线表示转义,两个斜线才表示一个真正的斜线
// 移植性非常差,不利于维护
fs.readFile('F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\代码\\07-绝对路径.js', 'utf8', function (err, dataStr) {
if (err) {
return console.log('读取失败');
}
console.log('读取成功');
})
2.12 使用 _dirname完美解决路径动态拼接问题
__dirname表示当前文件所处的目录
// 1、导入 fs 文件系统模块
const fs = require('fs')
// 注意在js中一个斜线表示转义,两个斜线才表示一个真正的斜线
// 移植性非常差,不利于维护
// __dirname 获得当前执行文件所在目录的完整目录名,这个值不会跟着node所在的执行目录改变
fs.readFile(__dirname + '/files/1.txt', 'utf8', function (err, dataStr) {
if (err) {
return console.log('读取失败');
}
console.log('读取成功');
})
console.log(__dirname);//F:\黑马年度班2020.8.30\四阶段前后端交互\第四章node.js\代码
3、node-path模块
3.1 了解path模块
path 模块是 node.js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求
- path.join()方法,用来将多个路径片段拼接成一个完整的路径字符串
- path.basename()方法,用来从路径字符串中,将文件名解析出来
3.2 路径拼接
1、path.join()的语法格式
使用path.join()方法,可以把多个路径片段拼接为完整的路径字符串,语法格式如下:
path.join([...paths])
- …paths 路径片段的序列
- 返回值
const pathStr=path.join('/a','/b/c','../','./d','e')
console.log(pathStr) // 输出 \a\b\d\e
const pathStr2=path.join(__dirname,'./files/1.txt')
console.log(pathStr2)// 输出 当前文件所在目录\files\1.txt
今后凡是涉及到路径拼接的操作,都要使用 path.join() 方法进行处理,不要直接使用 + 进行字符串的拼接
3.3 获取路径中的文件名
使用 path.basename()方法,可以获取路径中的最后一部分,经常通过找个方法获取路径中文件名,语法格式如下:
path.basename(path[,ext])
- path:必选参数,表示一个路径的字符串
- ext:可选参数,表示文件扩展名
- 返回:表示路径中的最后一部分
const path = require('path')
const fpath = '/a/b/c/index.html' // 文件的存放路径
var fullName = path.basename(fpath)
console.log(fullName);// 输出 index.html
var nameWithoutExt = path.basename(fpath, '.html')
console.log(nameWithoutExt);// 输出 index
注意,如果写了两个参数,那么它的返回值,只有文件名,没有文件的格式,如果写了一个参数,那么它的返回值,会有文件名和文件的格式
3.4 path.extname() 获取路径中的文件扩展名
path.extname(path)
- path:必选参数,表示一个路径的字符串
- 返回值:返回得到的扩展名字符串
const path = require('path')
const fpath = '/a/b/c/index.html' // 路径字符串
const fext = path.extname(fpath)
console.log(fext); // 输出 .html
4、时钟案例
案例要实现的功能
- 将index.html 页面拆分成三个文件,分别是index.css index.js index.html 并且将拆分出来的3个文件,
- 并且存放到 clock 目录中
案例的实现步骤
- 创建两个正则表达式,匹配 style script 标签
- 使用 fs 模块,读取需要被处理的 HTML 文件
- 自定义 resolveCSS 方法,来写入 index.css 样式文件
- 自定义 resolveJS 方法,来写入 index.js 脚本文件
- 自定义 resolveHTML 方法,来写入 index.html文件
4.2 定义正则表达式
// 导入 fs path 模块
const fs = require('fs')
const path = require('path')
// 匹配 <style></style> 标签的正则
// \s 表示空白字符,\S 表示非空白字符,*号表示匹配任意次
// style标签的 斜线会和正则的斜线冲突,需要转义
const regStyle = /<style>[\s\S]*<\/style>/
const regScript = /<script>[\s\S]*<\/script>/
4.3 读取内容
4.4 自定义resolveCSS方法 提取 css部分
// 导入 fs path 模块
const fs = require('fs')
const path = require('path')
// 匹配 <style></style> 标签的正则
// \s 表示空白字符,\S 表示非空白字符,*号表示匹配任意次
// style标签的 斜线会和正则的斜线冲突,需要转义
const regStyle = /<style>[\s\S]*<\/style>/
// 处理 css 样式
function resolveCSS(htmlStr) {
// 提取到 style标签的所有内容
const r1 = regStyle.exec(htmlStr)
// 将提取的内容做进一步处理
const newCSS = r1[0].replace('<style>', '').replace('</style>', '')
// 写入到 index.css文件中
fs.writeFile(path.join(__dirname, './clock/index.css'), newCSS, err => {
if (err) {
return console.log('写入文件失败!');
}
console.log('写入成功!');
})
}
4.5 自定义 resolveJS方法提取js部分
// 导入 fs path 模块
const fs = require('fs')
const path = require('path')
const regScript = /<script>[\s\S]*<\/script>/
function resolveJS(htmlStr) {
// 提取到 style标签的所有内容
const r2 = regScript.exec(htmlStr)
// 将提取的内容做进一步处理
const newJS = r2[0].replace('<script>', '').replace('</script>', '')
// 写入到 index.css文件中
fs.writeFile(path.join(__dirname, './clock/index.js'), newJS, err => {
if (err) {
return console.log('写入文件失败!');
}
console.log('写入成功JavaScript!');
})
}
4.6 自定义resolveHTML方法提取 html 脚本方法
function resolveHTML(htmlStr) {
const newHTML = htmlStr.replace(regStyle, '<link rel="stylesheet" href="./index.css">').replace(regScript, '<script src="./index.js"></script>')
fs.writeFile(path.join(__dirname, './clock/index.html'), newHTML, err => {
if (err) {
return console.log('写入文件失败!');
}
console.log('写入成功JavaScript!');
})
}
- writeFile 方法,的路径,中的那个文件必须先创建
- 重复调用writefile 方法 最新的会覆盖掉以前的
4.7 整个案例源码
// 导入 fs path 模块
const fs = require('fs')
const path = require('path')
// 匹配 <style></style> 标签的正则
// \s 表示空白字符,\S 表示非空白字符,*号表示匹配任意次
// style标签的 斜线会和正则的斜线冲突,需要转义
const regStyle = /<style>[\s\S]*<\/style>/
const regScript = /<script>[\s\S]*<\/script>/
fs.readFile(path.join(__dirname, './index.html'), 'utf8', (function (err, dataStr) {
// 读取文件失败的适合
if (err) {
return console.log('读取HTML文件失败');
}
// 读取成功后,调用对应的方法,拆解出 css js html 文件
resolveCSS(dataStr)
resolveJS(dataStr)
resolveHTML(dataStr)
}))
// 处理 css 样式
function resolveCSS(htmlStr) {
// 提取到 style标签的所有内容
const r1 = regStyle.exec(htmlStr)
// 将提取的内容做进一步处理
const newCSS = r1[0].replace('<style>', '').replace('</style>', '')
// 写入到 index.css文件中
fs.writeFile(path.join(__dirname, './clock/index.css'), newCSS, err => {
if (err) {
return console.log('写入文件失败!');
}
console.log('写入成功CSS!');
})
}
function resolveJS(htmlStr) {
// 提取到 style标签的所有内容
const r2 = regScript.exec(htmlStr)
// 将提取的内容做进一步处理
const newJS = r2[0].replace('<script>', '').replace('</script>', '')
// 写入到 index.css文件中
fs.writeFile(path.join(__dirname, './clock/index.js'), newJS, err => {
if (err) {
return console.log('写入文件失败!');
}
console.log('写入成功JavaScript!');
})
}
function resolveHTML(htmlStr) {
const newHTML = htmlStr.replace(regStyle, '<link rel="stylesheet" href="./index.css">').replace(regScript, '<script src="./index.js"></script>')
fs.writeFile(path.join(__dirname, './clock/index.html'), newHTML, err => {
if (err) {
return console.log('写入文件失败!');
}
console.log('写入成功JavaScript!');
})
}
5、node-http模块
5.1 什么是 http模块
客户端就是负责消费资源的电脑,服务器:负责对外提供网络资源
http模块是 node.js 官方提供的、用来创建web服务器的模块,通过http模块提供的 http.createServer() 方法,就能方便的把一台普通的电脑,变成一台web服务器,从而对外提供web资源服务
如果希望使用 http 模块创建web服务器,则需要先导入它
const http=require('http')
5.2 进一步理解 http 模块的作用
服务器和普通电脑的区别在于,服务器安装了 web服务器软件,例如:IIS、Apache等。通过安装这些服务器软件,就能把一台普通的电脑编程一台web服务器。
在node.js中,我们不需要使用 IIS、Apache 等这些 第三方web服务器软件。因为我们可以基于node.js提供的 http 模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供 web 服务
6、node-服务器概念
6.1 服务器相关的概念-IP地址
IP地址就是互联网上每一台计算机的唯一地址,因为 IP地址具有唯一性,如果把 “个人电脑” 比作 “ 一台电话” ,那么 “IP地址” 就相当于 “ 电话号码” ,只有在知道对方 IP 地址的前提下,才能与对应的电脑之间进行数据通信
IP地址的格式:通常用 “点分十进制 ” 表示(a,b,c,d)的形式,其中a,b,c,d都是 0~255 之间的十进制整数,例如:用点分十进制表示的IP地址(192.168.1.1)
- 互联网每台 web服务器,都有自己的IP地址,例如:大家可以在windows 终端中运行 ping www.baidu.com 命令,即可查看到百度服务器的 IP地址
- 在开发期间,自己的电脑既是一台服务器,也是一个客户端,为了方便测试,可以在自己的浏览器中输入 127.0.0.1 这个 IP 地址,就能把自己的电脑当作一台服务器进行访问了
6.2 服务器相关的概念-域名和域名服务器
尽管 ip 地址能够唯一地标记网络上的计算机,但 IP 地址是一长串数字,不直观,而且不方便记忆,于是人们发明了另一套字符型的地址方案,即所谓的域名地址
IP 地址 和 域名 是 一 一 对应的关系,这份对应关系放在一种叫域名服务器(DNS)的电脑中,使用者只需要通过好记的域名访问对应的服务器即可,对应的转换工作由域名服务器实现。因此,域名服务器就是提供 IP 地址和域名之间的转换服务的服务器
- 单纯使用 IP 地址,互联网中的电脑也能够正常工作。但是有了域名的加持,就让互联网的世界变得更加方便
- 在开发测试期间,127.0.0.1 对应的域名就是 localhost ,他们都代表我们自己的这台电脑,在使用效果上没有任何区别
6.3 服务器相关的概念-端口号
计算机中的端口,就好像是现实生活中的门牌号一样,通过门牌号,外卖小哥可以在整栋大楼众多的房间中,准确把外卖送到你的手中
同样的道理,在一台电脑中,可以运行成百上千个web服务。每个web服务都对应一个唯一的端口号。客户端发送过来的网络请求,通过端口号,可以被准确的交给对应的web服务进行处理
- 在实际应用中,URL中的80端口可以被省略
- 每个端口号不能同时被多个 web服务占用
7、node-创建基本web服务器
7.1 了解实现的步骤和核心代码
- 导入 http 模块
- 创建 web 服务器对象实例
- 为服务器实例绑定 request 事件,监听客户端的请求
- 启动服务器
7.2 通过四个核心步骤创建基本的web服务器
// 1、导入http模块
const http = require('http')
// 2、创建web服务器实例
const server = http.createServer()
// 3、为服务器实例绑定 request 事件,监听客户端请求
// 只要有人请求这个地址,就会触发 request 事件
server.on('request', function (req, res) {
console.log('Someone vist our web server.');
})
// 4、启动服务器
// listen的参数(端口号,回调函数)
server.listen(80, function () {
console.log('server running at http://127.0.0.1:80');
})
// 运行在 80 端口 可以省略,非80端口不可以省略
7.3 req 请求对象
只要服务器接收到了客户端的请求,就会调用通过 server.on() 为服务器绑定的 request 事件处理函数
如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下的方式:
- req 是请求对象,它包含了与客户端相关的数据和属性
- req.url 是客户端请求的 URL 地址
- req.method 是客户端的 method 请求类型
- req.headers 客户端的请求头信息 它是一个对象
ctrl +c 终止服务器
// 1、导入http模块
const http = require('http')
// 2、创建web服务器实例
const server = http.createServer()
// 3、为服务器实例绑定 request 事件,监听客户端请求
// 只要有人请求这个地址,就会触发 request 事件
server.on('request', function (req, res) {
console.log(req.method);
console.log(req.url);
console.log('Someone vist our web server.');
})
// 4、启动服务器
server.listen(80, function () {
console.log('server running at http://127.0.0.1:80');
})
// 运行在 80 端口 可以省略,非80端口不可以省略
输出的结果
// 输出的URL 是从 斜线后面开始的
Someone vist our web server.
GET
/
7.4 res响应对象
在服务器的 request 事件处理函数中,如果想访问与服务器相关的数据或者属性,可以使用如下的方式
- res 是响应对象,它包含了与服务器相关的数据和属性
- res.end() 向客户端发送指定的内容(就是响应到页面上),并结束这次请求的处理过程
- res.setHeader() 设置响应头,
server.on('request', function (req, res) {
console.log(req.method);
console.log(req.url);
console.log('Someone vist our web server.');
console.log(res.end('响应回去的数据'));
})
7.5 解决中文乱码问题
res.setHeader('Content-Type', 'text/html;charset=utf-8')
server.on('request', function (req, res) {
console.log(req.method);
console.log(req.url);
console.log('Someone vist our web server.');
res.setHeader('Content-Type', 'text/html;charset=utf-8')
console.log(res.end('响应回去的数据'));
})
在地址栏输入 127.0.0.1 后,会在页面显示 响应回去的数据
8、node-根据不同的url响应不同的html内容
8.1 实现步骤
- 获取请求的url地址
- 设置默认的响应内容为 404
- 判断用户请求的是否为 / 或者index.html 首页
- 判断用户请求的是否为 / about.html 关于页面
- 设置 Content-Type 响应头,防止中文乱码
- 使用 res.end() 把内容响应给客户端
const http = require('http')
const server = http.createServer();
server.on('request', (req, res) => {
const url = req.url // 获取用户请求的url
let content = `<h1>404 not found</h1>`
if (url == '/' || url == '/index.html') {
content = `<h1>首页</h1>`
}
else if (url == '/about.html') {
content = `<h1>关于页面</h1>`
}
res.setHeader('Content-Type', 'text/html;charset=utf-8')
res.end(content)
})
server.listen(80, function () {
console.log('server running at http://127.0.0.1:80');
})
9、node-时钟web服务器案例
9.1 介绍核心实现思路
把文件的实际存放路径,作为每个资源的请求url地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0KXG6ybV-1620388232597)(node.assets/image-20201003215051711.png)]
9.2 实现步骤
- 导入需要的模块
- 创建基本的web服务器
- 将资源的请求url 地址映射为文件的存放路径
- 读取文件内容并响应给客户端
- 优化资源的请求路径
// 1、导入node三大模块
const http =require('http')
const fs =require('fs')
const path = require('path')
// 2、创建web服务器
const server = http.createServer()
server.on('request', (req, res) => {
})
server.listen(80, () => {
console.log('server running at http://127.0.0.1');
} )
9.3 将资源的请求 url 地址映射为文件的存放路径
server.on('request', (req, res) => {
// 获取i请求的url 地址
/*
/clock/index.html
/clock/index.css
/clock/index.js
*/
const url = req.url
// 把请求的url地址映射为具体文件的存放路径
const fpath = path.join(__dirname, url)
})
9.4 读取文件的内容并响应给客户端
// http://127.0.0.1/clock/index.html
// 1、导入node三大模块
const http = require('http')
const fs = require('fs')
const path = require('path')
// 2、创建web服务器
const server = http.createServer()
server.on('request', (req, res) => {
res.setHeader('Content-Type', 'text/html;charset=utf-8')
// 获取i请求的url 地址
/*
/clock/index.html
/clock/index.css
/clock/index.js
*/
const url = req.url
// 把请求的url地址映射为具体文件的存放路径
const fpath = path.join(__dirname, url)
// 根据映射过来的文件路径读取文件
fs.readFile(fpath, 'utf8', (err, dataStr) => {
// 若读取失败
if (err) {
return res.end('404 Not fount!!')
}
// √
res.end(dataStr)
})
})
server.listen(80, () => {
console.log('server running at http://127.0.0.1');
})
9.5 优化资源的请求路径
- 输入127.0.0.1 访问的就是 index.html才行
- 路径太长,省略clock
// http://127.0.0.1/clock/index.html
// 1、导入node三大模块
const http = require('http')
const fs = require('fs')
const path = require('path')
// 2、创建web服务器
const server = http.createServer()
server.on('request', (req, res) => {
// res.setHeader('Content-Type', 'text/html;charset=utf-8')
// 获取i请求的url 地址
/*
/clock/index.html
/clock/index.css
/clock/index.js
*/
const url = req.url
// 把请求的url地址映射为具体文件的存放路径
//const fpath = path.join(__dirname, url)
let fpath = ''
if (url == '/') {
fpath = path.join(__dirname, './clock/index.html')
console.log(fpath);
}
else {
fpath = path.join(__dirname, '/clock', url)
}
// 根据映射过来的文件路径读取文件
fs.readFile(fpath, 'utf8', (err, dataStr) => {
// 若读取失败
if (err) {
return res.end('404 Not fount!!')
}
// √
res.end(dataStr)
})
})
server.listen(80, () => {
console.log('server running at http://127.0.0.1');
})
10、node-模块化
10.1 学习目标
10.2 什么是模块化
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程,对于整个系统来说,模块时可组合、分解、更换的单袁
就是遵守固定的 规则,把一个大文件拆成独立并相互依赖的多个小模块
- 提高了代码的复用性
- 提高了代码的可维护性
- 可以实现按需加载
10.3 模块化规范相关的概念
模块化规范就是对代码进行模块化的拆分和组合时,需要遵守的那些规则
- 使用什么样的语法格式来引用模块
- 在模块中使用什么杨的语法格式向外暴露成员
模块化规范的好处:大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的相互调用,利人利己
10.4 了解node中模块的三大分类
- 内置模块(内置模块是由node.js官方提供的,例如:fs、path、http等)
- 自定义模块(用户创建的每个 .js 文件,都是自定义模块)
- 第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载)
10.5 使用require方法加载模块
使用强大的 require() 方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用。
注意:使用 require()方法加载其他模块时,会执行被加载模块中的代码
// 加载内置的fs 模块
const fs = require('fs')
// 加载用户的自定义模块
const custom = require('./01.js')
// 加载第三方模块
const moment = require('moment')
10.6 使用 require 的小注意点
const m1 =require('./06.m1.js')
console.log(m1)// {}
注意:用require导入自定义模块的一瞬间,就会执行你整个自定义模块的所有代码,然后你的 m1 变量的输出是 { } 空对象
- 在使用 requir 加载用户自定义模块期间,可以省略 .js 的后缀名
10.7 了解模块作用域的概念以及好处
模块化作用域:和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内访问,这种模块级别的访问限制,叫做模块化作用域
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-whcepPvY-1620388232600)(node.assets/image-20201004171307617.png)]
模块作用域的好处
- 防止了全局变量污染的问题
- 只能在当前模块内访问
// 17-模块作用域
const username = "张三"
function sayHello() {
console.log('大家后' + username);
}
// 18-17测试
const custom = require('./17-模块作用域')
console.log(custom);
// 最后输出的是 {}
10.8 了解module对象
在每个 .js 自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息,打印如下
Module {
id: '.',
path: 'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\代码',
exports: {},
parent: null,
filename: 'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\代码\\17-模块作用域.js',
loaded: false,
children: [],
paths: [
'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\代码\\node_modules',
'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\node_modules',
'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\node_modules',
'F:\\黑马年度班2020.8.30\\node_modules',
'F:\\node_modules'
]
}
我们可以通过 exports 向外共享成员
10.9 了解module.exports对象的作用
在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用
外界用 require()方法导入自定义模块时,得到的就是 module.exports 所指向的对象
// 在一个自定义模块中,默认情况下,module.exports={}
// 在外界使用 require导入自定义模块的时候,得到的成员,就是那个模块 中 module.exports 指向的那个对象
const m = require('./19-自定义模块.js')
console.log(m);// {}
10.10 使用module.exports向外共享成员
// 19-自定义模块
// 在一个自定义模块中,默认情况下,module.exports={}
const age = 20
// 向module.exports 对象上挂载 username 属性
module.exports.username = '张三'
// 向module.exports 对象上挂载 sayHello 方法
module.exports.sayHello = function () {
console.log('Hello');
}
// 向module.exports 对象上挂载 age 属性
module.exports.age = age
//20-测试19
// 在外界使用 require导入自定义模块的时候,得到的成员,就是那个模块 中 module.exports 指向的那个对象
const m = require('./19-自定义模块.js')
console.log(m);//{ username: '张三', sayHello: [Function], age: 20 }
10.11 共享成员的注意点
使用require方法导入模块时,导入的结果,永远以module.exports指向的对象为准
即以 module.exports 最新的指向为准
// 21-共享成员的注意点
const age = 20
// 向module.exports 对象上挂载 username 属性
module.exports.username = '张三'
// 向module.exports 对象上挂载 sayHello 方法
module.exports.sayHello = function () {
console.log('Hello');
}
// 向module.exports 对象上挂载 age 属性
module.exports.age = age
// 让 module.exports 指向全新的对象
module.exports = {
nickname: '小黑',
sayHi: function () {
console.log('hi');
}
}
// 22-测试21
const m = require('./21-共享成员的注意点.js')
console.log(m);//{ nickname: '小黑', sayHi: [Function: sayHi] }
10.12 exports 对象
由于 module.exports 单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了 exports 对象。默认情况下,exports 和 module.exports 指向同一个对象。最终共享的结果,还是以 module.exports 指向的对象为准
10.13 exports和module.exports 的使用误区 案例1
时刻谨记,require()模块时,得到的永远是 module.exports 指向的对象
exports.username = 'zs'
module.exports = {
gender: '男',
age: 22
}
// 最后输出的是 {gender:'男',age:22}
10.14 exports和module.exports 的使用误区 案例2
module.exports.username='zs'
exports={
gender:'男',
age:22
}
// 最后输出的结果是:{username:'zs'}
10.15 exports和module.exports 的使用误区 案例3
exports.username='zs'
module.exports.gender='男'
// 最终输出的结果是:{username:'zs',gender:'男'}
10.16 exports和module.exports 的使用误区 案例4
exports={
username:'zs',
gender:'男'
}
module.exports=exports
module.exports.age='22'
// 最终输出的结果是:{username:'zs',gender:'男',age:'22'}
10.17 commonJS模块化规范
commonJS规定
- 每个模块内部,module变量代表当前模块
- module变量是一个对象,它的 exports属性,是对外的接口
- 加载某个模块,其实是加载该模块的 module.exports 属性,require()方法用于加载模块