1: 初识 node.js
//为什么JavaScript可以操作DOM和BOM
之所以能js能操作DOM和BOM, 是因为浏览器也内置了DOM和BOM
//浏览器中的JavaScript运行环境
代码能正常运行的必要环境
v8引擎负责解析和执行 js代码
内置API是运行环境提供的特殊接口, 只能在所属的运行环境中被调用
//借助node.js我们能用js做后端开发
node.js 也是基于 v8引擎的运行环境, 在node.js中是在做后端开发
node.js是做后端开发, node.js是无法调用DOM和BOM等浏览器内置API
学习node.js其实就是在学node中的API
//总结node.js 好学, 跟js一样, 先学内置方法,后学第三方模块!
node.js中的框架: express 可以快速创建web 应用
electron框架, 可以构建跨平台应用
restify 框架, 可以 快速构建 API接口项目
还可以读写数据库
node.js内置模块 (fs, path, http等) + 第三方API模块(express mysql)。。。
2: Node安装和使用
//---- 下载并安装Node ----
企业开发,下载LTS 版本, 属于稳定版
current 相当于测试版, 有新特性,有安全漏洞。 属于尝鲜版
//---- 查看已安装的Node.js的版本号 ----
查看node安装情况, win + r .输入cmd 即可打开终端。 运行 node -v 即可查看当前版本
//----- 了解终端的概念 -----
以后会经常用到终端, 所以要记住一些常用的命令
//----- 在Node.js环境中执行JavaScript代码 -----
把自己的js 放在命令中, 通过node来打印输出结果
1: 先切换到要执行的文件目录下: cd C:\Users\Administrator\Desktop\node
2: 在该目录下执行node 命令 : node 文件名, 就能显示js要输出的内容
//----- 使用更方便的形式执行Node命令 -----
以最快捷的方式打开命令行工具, 运行node 命令,执行文件
1: 按住shift不放, 鼠标右键 在此处打开 powershell , 运行 node xx 文件名,即可
2: win + r 输入 cmd,就能打开 cmd命令窗, cd 到文件处所的目录, node xx执行该文件
【cmd是最早版本的命令行工具, pw属于后者功能更强大, 但是两者都能满足我们开发】
//----- 了解常用的终端快捷键 -----
4 大常用命令
↑ 使用上一次,执行过的命令
tab 键, 输入文件名,首字母就能补全文件名称
esc 键,如果输入命令的过程中,有打错了子, cls能快速清空命令,重新再来输入
cls , 命令窗口已经跑了很多行,很花。 cls清空命令窗口,很简洁
3: 内置node-fs模块
// -------------------- 使用node向其他文件中写入内容 ---------------------
const fs = require('fs');
fs.writeFile('./files/test.txt', 'ok123', function (err) {
if (err) {
return console.log('文件写入失败!' + err.message);
}
console.log('文件写入成功!');
});
3.1: fs 读写案例
const fs = require('fs');
// 1: 读取文件
fs.readFile('./A/score.txt', 'utf8', function (err, dataStr) {
if (err) {
return console.log('读取文件失败!' + err.message);
}
// 2:使用split 【将字符串转换为数组】
// console.log(dataStr) // 小红=99 小白=100 小黄=70 小黑=66 小绿=88
const arrOld = dataStr.split(' ');
// console.log(arrOld) // [ '小红=99', '小白=100', '小黄=70', '小黑=66', '小绿=88' ]
// 3:使用forEach遍历数组中的每一项,将每一项中的 【= 替换成 :】 , 放入新数组中
const arrNew = [];
arrOld.forEach((item) => {
arrNew.push(item.replace('=', ':'));
});
// 4:将【数组转换为字符串】, 并回车换行
console.log(arrNew); // [ '小红:99', '小白:100', '小黄:70', '小黑:66', '小绿:88' ]
const newStr = arrNew.join('\r\n'); // \n 换行 \r 回车
console.log(newStr); // 小红:99 小白:100 小黄:70 小黑:66 小绿:88
// 5. 调用 fs.writeFile() 方法,把处理完毕的成绩,写入到新文件中
fs.writeFile('./B/score-OK.txt', newStr, function (err) {
if (err) {
return console.log('写入文件失败!' + err.message);
}
console.log('成绩写入成功!');
});
});
3.2: 使用__dirname解决路径动态拼接的路径问题
--------------------- __dirname 表示当前文件所处的目录 ---------------------
// console.log(__dirname)
fs.readFile(__dirname + '/files/1.txt', 'utf8', function (err, dataStr) {
if (err) {
return console.log('读取文件失败!' + err.message);
}
console.log('读取文件成功!' + dataStr);
});
最简单的解决方式是, 直接把该文件的完整路径写全在那, 但是要记得给每个\\斜杠前面多加一斜杠,
进行转义。 才能被正常识别, 【看似美好, 但是太长,不易维护】
__dirname能表示绝对路径,用它拼接文件名称,在命令窗口中不管cd几层, 不能在 node执行命令的时候,
把文件路径补全后,都能正常返回补全的地址,从而打印争取到正确的信息
4: path 处理路径拼接模块
// ------------------------- path.join方法的使用 ---------------------------------
const path = require('path');
const fs = require('fs');
fs.readFile(
path.join(__dirname, './files/1.txt'),
'utf8',
function (err, dataStr) {
if (err) {
return console.log(err.message);
}
console.log(dataStr);
}
);
// ------------------------- path.basename方法的使用 --------------------------------
// 定义文件的存放路径
const fpath = '/a/b/c/index.html'
const nameWithoutExt = path.basename(fpath, '.html')
console.log(nameWithoutExt)
// ------------------------- path.extname的使用 --------------------------------
// 这是文件的存放路径
const fpath = '/a/b/c/index.html'
const fext = path.extname(fpath)
console.log(fext)
path.join方法的实际使用:
1:../是能抵消期前一个 /盘符的
2:以后只要涉及到文件路径拼接, 都需要使用path.join(__dirname, './文件名称'), 它的好处就是,
哪怕多了文件路径中多了一个. 。也能正常访问到,它自带忽略功能
path.basename的2种使用方法
1: 获取完整的文件名: path.basename(文件地址), 返回文件名, 带文件后缀的
2:只获取文件名,不带后缀。path.basename(文件地址, 要忽略的文件后缀名称)
path.extname 获取文件后缀名
path.extname(文件地址), 能自动获取地址中文件的后缀名称。
4.1: (读写、路径拼接) 倒计时案例
倒计时案例 - 伪代码:实现思路:
// -------- 介绍需求并分析案例的实现步骤 ------------
1: 要实现的页面效果
2:要实现的目标: 将css和html以及js,拆分成3个不同的文件,最后3合1,变成一个完整的案例
3:实现流程分析:
3.1:使用正则表达式,来匹配<style><script>这2个标签
3.2:使用fs.readFile读取文件
3.3:自定义3个方法,分别获取到js+css+html
// ---------- 定义正则表达式 ------------------
定义2个正则表达式,一个用来获取js,另一个用来获取css
1:匹配css: /<style>[\s\S]*<\/style>/ , \s表示空白字符,\S表示非空白字符串, \转义
2:匹配js:/<script>[\s\S]*<\/script>/, 同上一致
// ------------ 使用fs.readFile方法读取HTML文件的内容 -------------
调用fs.readFile方法读取文件内容
配合path.join方法拿到绝对路径下的文件, 将文件内容读取出来。
// ---------- 自定义resolveCSS方法提取样式表文件 -----------
实现提炼和抽取纯css代码
1:封装代码,拿到读取的结果: resolveCss(读取到的文件内容)
2:使用之前定义好的regStyle去匹配<style>标签中的内容: reg.exec(读取到的数据), 此时匹配到style中,是一个字符串。
3:使用replace方法将style标签替换掉,变成真正的css代码:r1[0].replace,将索引为0的这一项替换掉,在使用该方法,('<style>', '')将style标签替换成空,拿到真正的css代码
4:将纯css代码写入到新的文件中: 调用fs.writeFile(绝对路径, '写入到那个文件'), 要写入的内容。写入成功就提示。【此时该文件夹中就多了该文件】
// ----------- 自定义resolveJS方法提取JS脚本文件 -----------
实现提炼js抽取纯js文件 【同上一致】
1:调用函数获取到读取的文件内容
2:使用正则表达式读取想要的js代码
3:将script标签替换掉,变成纯js代码
4:将纯js代码抽离到单独的新文件中
5:将内容成功写入到新的文件中
// -------- 自定义resolveHTML方法提取html文件 -----------
完成页面重构
1:完成页面重构:流程:调用函数拿到读取的文章内容, 内容通过css正则表达式,将页面中的css代码和js代码替换成外链的地址。然后调用fs.reafFile将调整后的内并到index.html中
1.1: 调用函数接收,文件读取的内容
1.2:内容调用replace替换掉(把谁替换【正则表达式匹配到的内容】,替换成什么)。替换后形成了完整的页面。
1.3:将这个完整的新页面,写入到指定问文件中,提示写入成功的信息。 打开查看,确实是以外链的方式引入该文件的【完成修改,完成案例】
// ------- 案例的两个注意点 --------
2个注意点:
注意点1: fs.wrireFile只能写入建好的文件夹中, 如果没有该文件夹,直接去创建这个文件会报错,必须先有文件夹才能添加新文件
注意点2:多次使用res.readFile会每次覆盖之前写的内容【长江后浪推前浪】
倒计时案例 - 代码实现流程:
// ------------------------- 倒计时读写.js-----------------------
const fs = require('fs');
const path = require('path');
// 1: 定义正则表达式,分别匹配 <style></style> 和 <script></script> 标签
const regStyle = /<style>[\s\S]*<\/style>/;
const regScript = /<script>[\s\S]*<\/script>/;
// 2: 调用 fs.readFile() 方法读取文件
fs.readFile(
path.join(__dirname, '../素材/index.html'),
'utf8',
function (err, dataStr) {
// 2.1: 读取 HTML 文件失败
if (err) return console.log('读取HTML文件失败!' + err.message);
// 2.2: 读取文件成功后,调用对应的三个方法,分别拆解出 css, js, html 文件
resolveCSS(dataStr);
resolveJS(dataStr);
resolveHTML(dataStr);
}
);
// 3: 定义处理 css 样式的方法
function resolveCSS(htmlStr) {
// 3.1: 使用正则提取需要的内容
const r1 = regStyle.exec(htmlStr);
// 3.2: 将提取出来的样式字符串,进行字符串的 replace 替换操作
const newCSS = r1[0].replace('<style>', '').replace('</style>', '');
// 3.3: 调用 fs.writeFile() 方法,将提取的样式,写入到 clock 目录中 index.css 的文件里面
fs.writeFile(
path.join(__dirname, './clock/index.css'),
newCSS,
function (err) {
if (err) return console.log('写入 CSS 样式失败!' + err.message);
console.log('写入样式文件成功!');
}
);
}
// 4: 定义处理 js 脚本的方法
function resolveJS(htmlStr) {
// 4.1: 通过正则,提取对应的 <script></script> 标签内容
const r2 = regScript.exec(htmlStr);
// 4.2: 将提取出来的内容,做进一步的处理
const newJS = r2[0].replace('<script>', '').replace('</script>', '');
// 4.3: 将处理的结果,写入到 clock 目录中的 index.js 文件里面
fs.writeFile(path.join(__dirname, './clock/index.js'), newJS, function (err) {
if (err) return console.log('写入 JavaScript 脚本失败!' + err.message);
console.log('写入 JS 脚本成功!');
});
}
// 5:定义处理 HTML 结构的方法
function resolveHTML(htmlStr) {
// 5.1: 将字符串调用 replace 方法,把内嵌的 style 和 script 标签,替换为外联的 link 和 script 标签
const newHTML = htmlStr
.replace(regStyle, '<link rel="stylesheet" href="./index.css" />')
.replace(regScript, '<script src="./index.js"></script>');
// 5.2: 写入 index.html 这个文件
fs.writeFile(
path.join(__dirname, './clock/index.html'),
newHTML,
function (err) {
if (err) return console.log('写入 HTML 文件失败!' + err.message);
console.log('写入 HTML 页面成功!');
}
);
}
5: http模块创建web服务器
5.1: http模块和服务器软件的区别
//--------------------- 初识 http模块的作用和用法 ---------------------
node 内置方法http能通过他的http.createServer( ) ,用本机创建一台web服务器
//-------------------- 服务器与电脑的区别,以及如何使用软件启动web服务器 -------------------------
1:服务器与电脑的区别: 装了web服务器软件,电脑就能变成一台web服务器
2:phtStudy能通过启动Aphche,获取web服务器的能力。只要把自己的写好的文件放进它的网站根目录,通过浏览器的127.0.0.1就能访问到这个网页了
【但是node的http模块, 能通过几行代码快速创建一个web服务器】
5.2 服务器相关的概念
//---------- IP地址的规则,和现实网站中的IP地址,以及自己的IP地址 -----------------
1:IP地址的规则: 十进制,0-255之间, . 逗号分隔。是互联网每台电脑的唯一地址,相当于个人的电话号码
2:现实网站中的IP地址:如果在cmd命令窗口中输入 ping www.baidu.com就能看到该网站的IP地址,我们把该IP地址放在浏览器中,也能照常访问百度
3:自己的IP地址:开发前进,我们的电脑和服务器于一体,通过127.0.0.1来开发测试。就能把自己的电脑当做一台web服务器来使用
//----------- 域名是如何形成的, 和本机的id地址也可被域名代替 ---------------
1:域名是如何形成的: 域名就是ip地址的别名,是DNS把id地址转换成了域名,方便我们记忆
2:本机的id地址也可被域名代替: 127.0.0.1能被 localhsot代替,也是能正常访问的
//---------- 端口号的具体含义,和端口号的唯一性 ---------------
1:端口号的具体含义: 端口号就好比房间号,具有唯一性
2:端口号的唯一性: 端口号好比试衣间,1个端口只能启动一个服务。第二个同名端口就会启动失败并报错。现实中80端口浏览器默认携带,可以不输入, 非80端口必须携带
5.3: http模块创建web服务器
5.3.1: 创建最基本的web服务器实现的核心步骤
5.3.2: 使用http模块创建web服务器
// 1. 导入 http 模块
const http = require('http')
// 2. 创建 web 服务器实例
const server = http.createServer()
// 3. 为服务器实例绑定 request 事件,监听客户端的请求
server.on('request', function (req, res) {
console.log('Someone visit our web server.')
})
// 4. 启动服务器
server.listen(8080, function () {
console.log('server running at http://127.0.0.1:8080')
})
5.3.3: req请求对象
// -------------------- 通过request请求对象,将url请求地址和method请求方式打印 ---------------------
const http = require('http')
const server = http.createServer()
//1: req 是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req, res) => {
//1.1: req.url 是客户端请求的 URL 地址
const url = req.url
//1.2: req.method 是客户端请求的 method 类型
const method = req.method
const str = `Your request url is ${url}, and request method is ${method}`
console.log(str) // Your request url is /, and request method is GET
// 调用 res.end() 方法,向客户端响应一些内容
res.end(str)
})
server.listen(80, () => {
console.log('server running at http://127.0.0.1')
})
5.3.4: res响应对象
//---------------------- 调用 res.end() 方法,向客户端响应一些内容 --------------------------
const http = require('http');
const server = http.createServer();
// req 是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req, res) => {
// req.url 是客户端请求的 URL 地址
const url = req.url;
// req.method 是客户端请求的 method 类型
const method = req.method;
const str = `Your request url is ${url}, and request method is ${method}`;
console.log(str); // Your request url is /, and request method is GET
// 调用 res.end() 方法,向客户端响应一些内容
res.end(str);
});
server.listen(80, () => {
console.log('server running at http://127.0.0.1');
});
5.3.5: res.setHeader防止中文乱码问题
//----------------------- 设置 Content-Type 响应头,解决中文乱码的问题 -----------------------
const http = require('http')
const server = http.createServer()
server.on('request', (req, res) => {
// 定义一个字符串,包含中文的内容
const str = `您请求的 URL 地址是 ${req.url},请求的 method 类型为 ${req.method}`
// 调用 res.setHeader() 方法,设置 Content-Type 响应头,解决中文乱码的问题
res.setHeader('Content-Type', 'text/html; charset=utf-8')
// res.end() 将内容响应给客户端
res.end(str)
})
server.listen(80, () => {
console.log('server running at http://127.0.0.1')
})
6: req.url不同地址,显示不同页面
// ----------------- req.url不同地址,显示不同页面 -------------------------
const http = require('http')
const server = http.createServer()
server.on('request', (req, res) => {
const url = req.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, () => {
console.log('server running at http://127.0.0.1')
})
7: web服务器 时钟案例
//---------------------------- web服务器 时钟案例 --------------------------------------
const http = require('http')
const fs = require('fs')
const path = require('path')
const server = http.createServer() // 1:创建web服务器
server.on('request', (req, res) => { // 2:监听如Request事件
const url = req.url// 3: 拿到浏览器请求地址
let fpath = '' // 4:准备文件存放的路径
if (url === '/') { // 5:请求地址不同,展示不同的页面
fpath = path.join(__dirname, './clock/index.html')
} else {
fpath = path.join(__dirname, '/clock', url)
}
fs.readFile(fpath, 'utf8', (err, dataStr) => { // 6:读取fpath中存储的页面,
if (err) return res.end('404 Not found.') // 7: 如果请求错误,显示404
res.end(dataStr) // 8:将请求到了clock.html页面展示到浏览器中
})
})
server.listen(80, () => {// 9:监听80:端口
console.log('server running at http://127.0.0.1')
})
8: node - 模块化
8.1:模块化概念
编程中的模块化, 就是把一个大的文件拆分为多个小文件,
好处就是: 提高了代码的复用性,可维护性,可实现按需加载
模块化规范降低了沟通成本, 方便了模块之间的调用
模块化分为3大类:
内置模块: 由node.js官方自己提供, 例如:fs, path,http等
自定义模块: 用户创建的每个js文件,都是自定义模块
第三方模块: 需要提前下载使用,
8.2:require 加载模块
3种方式加载模块
1: 内置模块的加载: const fs = require('fs')
2: 加载用户自定义的模块: const result = require('./b.js')
3: 加载第三方模块: const moment = require('monent')
可以省略后缀名称也能正常访问到
8.3:模块作用域
模块作用域调用的变量,方法等成员,只能在当前模块内部访问。
其他文件不能过来访问,是为了防止全局变量的污染。会返回一个空对象
8.4:module.exports 向外导出
//---------------- 了解module对象 -------------------
module对象, Module是一个对象,里面包含了ID,name,exports等属性
在其中module.exports最为重要
//------------------ 了解module.exports对象的作用 ----------------------------
module.exports= { } 默认等于空对象。
//------------------ 使用module.exports向外共享成员 ---------------------------
module.exports 能导出变量,方法, 属性等。 导出的hi被打印成一个空对象{ }
8.5: module.exports和exports的区别:
//------------------------ 共享成员是的注意点 --------------------------
如果module.exports导出的是单独的属性或者变量,或者是方法。但是当module.exports={ }等于一个对象时,
他是以对象为准,只会打印对象中的内容, 对象之外的导出都是无效的了。【modulex.exports={ } 他是最大级别。以它为准】
//------------------------ module.exports和exports的区别: ---------------------------
默认module.exports和exports是同一个对象,exports这种写法个更简洁些。
8.6:exports和module.exports使用误区:
//-------------------------------- 使用误区 -----------------------------------
如果exports和module.exports同时在一个页面, 并且module.exports={ } 那么exports这个会被忽略掉,因为权重没他高。
但是如果他们2个是在单独赋值时, 是等价的。不符出现覆盖问题。包括exports={ }, 然后把exports的对象,
赋值给module.exports,此时在module.exports.age =20, 往module.exports对象上追加属性,
就相当于在这个module.exports身上多了这个属性
【总结单独使用页面的module.exports,他们是等价的, 除非页面的mudole.exports={}, 对象级别是最高的, 会出现覆盖的】
8.7: CommonJS模块化规范
module.exports 是标准的向外导出
require 是导入