# 框架前置课155
**Repository Path**: flyird/framework-pre-course-155
## Basic Information
- **Project Name**: 框架前置课155
- **Description**: 黑马前端就业155期框架前置课仓库地址
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 1
- **Created**: 2023-05-03
- **Last Updated**: 2024-11-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# [了解]Node基础
## 系统内置终端软件
- Windows
- - cmd
- - - 在文件夹地址栏的位置,输入cmd,回车即可打开
- - powershell
- - - 在文件夹空白处,按住Shift,鼠标右键,选择“在此处打开powershell窗口”
- - Windows Terminal (win11自带的、win10去商店安装,重启电脑)
- Mac
- - 终端(建议安装 [**超级右键Lite**](https://apps.apple.com/cn/app/超级右键lite/id1552554632))+ [oh my zsh](https://gitee.com/laotang1234/ohmyzsh/wikis/使用说明)(终端美化工具)
- **也可以选择**安装 hyper 或者 iterm2 这样的终端软件。
这些终端软件中,也可以执行我们学习过的Git命令。
## vscode中的终端(可选)
vscode中的终端,使用的也是系统内置的终端。没什么新鲜的,只不过把界面集成到了vscode中而已。
- 点击vscode菜单栏(最上面一栏)中的“终端”,即可新建一个终端窗口。(不建议)
- 或者在侧边栏的文件上,鼠标右键,新建终端(建议)
- 或者按快捷键 `Ctrl + ~` 打开关闭终端(建议)
喜欢就用,不喜欢就算了。
## cd命令切换终端路径
cd - change directory 翻译为 改变目录。
```
# 切换到指定的文件夹
cd 文件夹名
# 切换到上层文件夹
cd ..
```
其他技巧:
- clear -- 清屏; cmd窗口的清屏是 cls
- 按 ↑ ↓ 箭头,可以找到历史命令
## 运行环境
浏览器是JS代码唯一的运行环境。JS代码只有在浏览器中才能够正常执行。
## NodeJS环境
Node是一个软件,需要下载安装。
Node是另一个JS的运行环境,JS代码可以在Node环境中正常运行。

ECMAScript,就是JS的核心语法,比如声明变量、函数、对象、数组,循环..................
浏览器特有的是 WebAPIs,比如DOM操作、事件注册等等,只能在浏览器中运行
内置模块是Node环境特有的,只能在Node环境中运行。
## 下载和安装Node
官方下载地址:https://nodejs.org/zh-cn/download/releases
```
node-v1x.xx.x-x64.msi ---- Windows系统,下载这种类型的
node-v1x.xx.x.pkg ---- Mac系统,下载这种类型的
```
安装,一直下一步,可以选择安装到你喜欢的盘符。
安装之后,没有任何桌面图标。
检测是否安装成功,打开 cmd 终端。运行 `node -v` ,如果查看到版本号,说明安装成功。
## 使用node命令执行JS文件(掌握)
此种方式,比较常用。可以运行 写到 “`xx.js`” 里面的JS代码,可以运行JS文件中的代码。
操作步骤:
- 打开终端,确保终止路径,刚好是代码文件夹。
- 输入 “`node 要执行的js文件`”回车表示运行
**为了方便找到js文件,最好在js代码文件夹,打开终端窗口**
如果你用的是vscode,在js文件上,鼠标右键,打开终端,这样的终端路径才是正确的。
**可能的问题**:
- 如果终端中出现 `>`符号,说明操作失误,按两次“Ctrl+C”退出
- 不能使用node运行html、css等等代码,因为node只是JS的运行环境。
- 不能在node环境中运行WebAPI的代码,比如 document、ajax,因为 document、ajax是浏览器环境的API。
- JS文件名,不能叫做 `node.js`,特殊记忆。
- 找文件的时候,可以按 tab 键,自动补全文件名。如果没有自动补全,说明终端路径错误。
## path模块
- path.join('路径1', '路径2', '路径3', ....................) --- 可以把给出的几部分路径拼接到一起
- __dirname 表示当前文件的绝对路径
- `path.join(__dirname, '01-test.js')` ---- 可以得到某个文件的绝对路径
> 后续,如果涉及到文件操作,优先使用绝对路径。
## fs模块
fs - file system 文件系统的意思。所有和文件、文件夹相关的操作,都通过这个模块完成。
```js
// path --- 路径相关
// fs --- file system 文件系统。这个模块中的方法,都是和文件有关系的。
const fs = require('fs') // 加载模块,得到对象
// --------------------- fs.readFile() -----------------------
// 作用:读取文件。获取文件里面的内容
// 特点:这个方法是异步方法(宏任务)
// 语法:
/**
* fs.readFile('文件路径文件名', 'utf-8', (err, data) => {
* data 表示读取的结果
* err 表示错误信息(没有错误err=null; 有错误err=对象)
* })
*/
// fs.readFile('06-test.txt', 'utf-8', (err, data) => {
// if (err) throw err // 有错误,err是对象,转成布尔是true,就throw err;遇到throw会终止代码执行
// console.log(data)
// })
// --------------------- fs.writeFile() -----------------------
// 作用:写入文件。就是把内容放到文件中
// 特点:1. 如果文件不存在,会自动创建文件(不会递归创建)
// 2. 如果文件存在并且里面有内容,则执行该方法之后,会将原有的内容覆盖
// 语法:
/**
* fs.writeFile('文件路径及文件名', '写入的内容', err => {
* 有错误,err是对象,转成布尔是true, 没有错误err=null,转成布尔就是false
* })
*/
fs.writeFile('07-test.txt', '离离原上草,一岁一枯荣', err => {
if (err) throw err
console.log('写入成功')
})
```
## 使用内置模块操作数据
创建 books.json
```json
[
{ "id": 1, "bookname": "西游记", "author": "唐僧" },
{ "id": 3, "bookname": "水浒传", "author": "宋江" },
{ "id": 4, "bookname": "斗破苍穹", "author": "土豆" }
]
```
要求:
1. 写代码,将所有的图书输出
2. 写代码,能够添加新的图书
```js
const { readFile, writeFile } = require('fs')
const { join } = require('path')
// 2. 写代码,能够添加新的图书
readFile(join(__dirname, '08-books.json'), 'utf-8', (err, data) => {
if (err) throw err
// console.log(data) // 得到json格式的字符串
let arr = JSON.parse(data)
// 向数组中,添加一本新的图书
arr.push({
id: 5,
bookname: '完美世界',
author: '辰东'
})
// console.log(arr)
// 重新写入文件,把全部的图书放到 books.json 中,把原来的覆盖掉
writeFile(join(__dirname, '08-books.json'), JSON.stringify(arr), err => {
if (err) throw err
console.log('添加完成')
})
})
```
## http模块
http模块用于搭建服务器。
基本代码:
```js
// 1. 导入http模块
const http = require('http')
// 2. 创建server实例对象
const server = http.createServer()
// 3. 注册request请求事件。客户端发来请求的时候,会触发该事件
server.on('request', (req, res) => {
// 事件处理函数,当客户端发来请求之后,就会触发这个函数
// 下面设置响应头,目的是告诉客户端,响应的结果是什么类型的数据,编码格式是什么
res.setHeader('Content-Type', 'text/html; charset=utf-8')
// 下面是设置响应结果,并做出响应
res.end('hello world')
})
// 4. 指定端口,启动服务
server.listen(3000, () => console.log('我的服务器启动了'))
```
在终端窗口中,运行 上述代码,表示启动服务了。
在浏览器中,输入 localhost:3000 ,回车,表示向服务器发送请求,会看到 hello world。
## 响应图书数据
还是接上面的代码,就是把上面两部分代码融合到一起。
```js
const { readFile, writeFile } = require('fs')
const { join } = require('path')
// 1. 导入http模块
const http = require('http')
// 2. 创建server实例对象
const server = http.createServer()
// 3. 注册request请求事件。客户端发来请求的时候,会触发该事件
server.on('request', (req, res) => {
// 事件处理函数,当客户端发来请求之后,就会触发这个函数
// 下面设置响应头,目的是告诉客户端,响应的结果是什么类型的数据,编码格式是什么
res.setHeader('Content-Type', 'text/html; charset=utf-8')
// 下面是设置响应结果,并做出响应
readFile(join(__dirname, '08-books.json'), 'utf-8', (err, data) => {
if (err) throw err
// res.end('hello world')
res.end(data)
})
})
// 4. 指定端口,启动服务
server.listen(3000, () => console.log('我的服务器启动了'))
```
重要:修改了代码,必须要重启服务才行
- 终端窗口中,按 Ctrl + C,多按几次,表示终止服务
- 重新运行上述代码,重新启动服务,这样,修改的代码才会生效
# [了解]网络基础
http://www.itcbc.com:3006/api/getbooks
http://123.57.104.105:3006/api/getbooks
http -- 协议
www.itcbc.com 域名(123.57.104.105 叫做IP地址) ---- 主机地址
3006 -- 端口号(http协议默认端口是80 https协议默认的端口是443),如果是默认端口可以不写
## 协议
### 什么是HTTP
**超文本传输协议**,是一个基于请求与响应,无状态的,应用层的协议,常基于TCP/IP协议传输数据,互联网上应用最为广泛的一种网络协议,所有的WWW文件都必须遵守这个标准。
**HTTP协议默认端口号是** **80**
### 什么是HTTPS
HTTPS 是身披 SSL外壳的 HTTP。HTTPS是一种通过计算机网络进行安全通信的传输协议,经由HTTP进行通信,利用SSL/TLS建立全信道,加密数据包。HTTPS使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私与完整性。
**HTTPS协议默认端口号是** **443**
**协议,它规定了双方(浏览器和服务器)应该如何传输数据。**
## 主机地址
**主机地址是作用是为了找到服务器**。
### IP地址
IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
比如生活中的地址,表示地理上的一个位置,通过这个地址可以找到这个地理位置。
同样的,互联网中的每一台主机电脑,都有一个地址。通过这个地址可以找到这台主机电脑。
**本机IP:127.0.0.1**
### 域名
形如 www.xxx.com 这样的就叫做域名,域名需要单独购买。购买后,需要绑定IP地址进行使用。绑定IP地址后,就可以通过域名找到主机电脑了。
**本机域名:localhost**
## DNS服务器
DNS服务器用于记录 IP地址和域名的对应关系。
前面说,域名和IP地址是绑定关系,那么某个域名绑定的IP地址是什么呢?这个对应关系就记录在DNS服务器当中。
通过DNS服务器可以解析出 一个域名对应的IP地址。
www.itcbc.com ----------------- 123.57.103.104
www.baidu.com ----------------- 23.89.134.189
## 端口号
**端口号的作用,就是区分服务器上的程序的。每个程序有一个端口号**。
所谓的端口,就好像是门牌号一样,客户端可以通过ip地址找到对应的服务器端
但是服务器端是有很多应用程序的,每个应用程序对应一个端口号,通过端口号,客户端才能真正的访问到该服务器上的应用程序。
为了对端口进行区分,将每个端口进行了编号,这就是端口号。
端口号的范围是 0 ~ 65535
如果一个应用程序使用了3006端口号,其他的应用程序就不能再使用3006端口号。
http 协议,默认端口:80
https 协议,默认端口:443
## 客户端请求服务器的步骤(重要)
当我们在浏览器地址栏输入 “http://www.xxx.com/api/getbooks”时或者使用Ajax发送请求,客户端是如何找到服务器并发送请求的?
简单的描述:
- 按回车后,先通过DNS服务器找到域名对应的IP地址
- 通过IP地址去请求服务器
\--------------------------------------------------------------------------------------------------------
**面试,只说大标题**,下面的1/2/3/4/5/6 即可。
1. 先找到服务器【必须得到IP地址】
1. 检测浏览器缓存有没有缓存该域名对应的IP地址。有则通过IP地址去找服务器
2. 检测本地的hosts文件,是否有记录该域名对应的IP地址,有则通过IP地址去找服务器
3. 通过DNS服务器解析,找到该域名对应的IP地址,然后通过IP地址去找服务器
2. 进行三次握手(建立连接,确认一下双方是否有发送数据和接收数据的能力)
1. 第一次握手是在建立连接,客户端发送连接请求报文段,把标有SYN的数据包发给服务器端即为接收端。
2. 第二次握手是服务器端即接收端收到客户端的SYN的报文段,同时发送标有SYN/ACK的数据包。
3. 第三次握手是客户端收到服务器端的SYN/ACK的数据包后,向服务器端发送标有ACK的数据包。
3. 发送请求,传输数据。。。
4. 服务器处理,并做出响应
5. 浏览器接收响应结果。
1. 处理数据,渲染到页面中(首次渲染会有重绘和回流)
6. 四次挥手(作用是断开连接)
# [面试]同源和跨域
## 同源
同源,说的是两个url之间的对比。如果两个url以下三个方面都相同,则这两个url同源,否则非同源。
- 协议(http、https、file、......)
- 主机地址(www.itcbc.com)
- 端口号(:3006)
## 同源策略
同源策略(同源政策)是**浏览器**的一种保护机制。
如果发送了一个请求,服务器返回结果后,浏览器会判断(检查)**打开页面的url** 和 **请求的接口地址**是否同源。
- 如果同源则接收响应结果
- 如果不同源,则拒绝接收结果(造成请求失败)
## 跨域
凡是违反了同源策略的请求,都是跨域请求。
我们这几天,请求的接口,都是跨域请求。正常来讲,都会请求失败。
> 目前,能够请求成功,是因为做了处理(见下文)
## 突破跨域的限制
### CORS方案
CORS,翻译过来,叫做 跨域资源共享。
- 用的多
- 是标准的解决跨域的方案
- 兼容性不好(IE10+)
- 支持所有的请求方式
- 用起来方便的不要不要的
我们课程中使用的全部接口都是使用CORS方案实现的
使用CORS方案解决跨域
- 只需要后端程序员在做出响应的时候,加一个响应头(`Access-Control-Allow-Origin: *`)即可。
- `res.setHeader('Access-Control-Allow-Origin', '*')`
- 前端程序员不需要做任何处理,正常发送Ajax请求即可。
### JSONP方案
前端先准备好一个函数,设置好形参。形参就是响应结果。
前端使用 script 的 src 向服务器发送请求,并传递 callback 参数,参数值就是我们准备好的函数名
后端的响应结果,就是调用函数,把响应的数据当做函数的实参传给我们前端。
前端示例代码:
```html
```
后端示例代码:
```js
res.end('abc(响应数据)')
```
# [重点]包和npm
## 介绍
### 什么是包
包,可以理解为是插件,或模块。不过这种包都是个人或公司开发的,并非node官方内置的。
我们称这种包为第三方包。
个人或公司开发完包,然后发布到[npm网站](https://www.npmjs.com/),我们可以下载并使用这些第三方包。
目前,npm网站收录了超过 300 万个第三方包。
不用担心学不完的问题,常用的包不超过100个。
### 包的分类
由于各种各样的插件五花八门,什么都有。
也就是说,可以把包按照用途分为几类:
- 项目包
1. 1. 项目核心依赖包
2. 项目开发依赖包
- 全局包
其中,项目包,也叫做本地模块,是开发项目所需的包。只适用于当前项目。要下载安装到当前项目文件夹。
全局包,一般都是命令,通过这些全局命令,帮助开发者简化开发。
### 什么是npm
npm(node package manage)node 包 管理器。
**通俗的讲,npm是一个下载、卸载、发布、... 包的工具**。
npm这个工具,在安装 node 的时候,就已经安装到你的计算机中了。
命令行中执行: `npm -v` ,如果看到版本号,说明安装成功了。
## 项目包
### 安装之前必须初始化
在项目文件夹,打开终端。(确保终端路径是项目文件夹才行)
执行 `npm init`,进行初始化。
- 回车后,会问包的名字叫什么,包的名字不能用中文和特殊符号。(符号只能用中横线)
- 其他问题,一路回车,直至再次出现终端路径为止,表示初始化完成
**初始化完成,会在项目文件夹生成 package.json 的文件**。
> 如果项目文件夹是没有中文和特殊符号的,可以 npm init -y 直接初始化完成。
### 如何安装、卸载
**只有在初始化的基础之上,才能够安装包**。
安装命令:
```
# 安装命令
npm install 包名
npm i 包名 --- 安装命令的简写
npm i 包名 包名 包名 --- 一次性安装多个包
npm i 包名@版本号 --- 安装指定的版本
npm i 包名 -D --- 安装开发依赖(开发阶段才能用得上,项目做完就用不上了)
# 卸载命令
npm uninstall 包名
npm un 包名 --- 卸载命令的简写
npm un 包名 包名 包名 --- 一次性卸载多个包
```
### 如何使用
moment 或 dayjs 这两个包,用于做时间日期处理。
如何使用这些包,答案就是查文档。
- 官网
- 百度一下,查一下使用的帖子
- npm网站,找到这个包,点进去,就会看到使用文档
下面演示dayjs的使用:
```js
// const fs = require('fs')
const dayjs = require('dayjs')
// 下面的方法,作用是格式化日期
// 语法,参考文档:https://dayjs.fenxianglu.cn/category/display.html#%E6%A0%BC%E5%BC%8F%E5%8C%96
// dayjs(时间默认是当前时间).format('格式化成什么样')
// 格式化当前日期
// console.log(dayjs().format('YYYY-MM-DD HH:mm:ss'))
// console.log(dayjs().format('YYYY-MM-DD'))
// console.log(dayjs().format('YYYY/MM/DD'))
// console.log(dayjs().format('YYYY年MM月DD日'))
console.log(dayjs().format('MMMM/DD YY'))
// 格式化指定的日期
// console.log(dayjs(1392323232321).format('YYYY年MM月DD日'))
```
## 全局包
### 如何安装、卸载
因为是全局安装,默认都会安装到系统盘。
所以就不用考虑终端路径问题了(终端路径是什么无所谓,因为无论路径是什么,都会安装到系统盘)
也不需要初始化。
安装卸载命令:
```
# 安装命令
npm install 包名 -g
npm install -g 包名
npm i 包名 -g
# 卸载命令
npm un 包名 -g
Mac系统:
sudo npm i 包名 -g ,回车后,输入开机密码,开机密码不显示
```
### 如何使用
全局安装 nrm
```
windows系统:
npm i -g nrm
Mac系统:
sudo npm i -g nrm
```
nrm 的作用是:切换下载地址(切换镜像源)
使用:
```
nrm ls ---- 查看有哪些镜像源可用
nrm use taobao ---- 切换镜像源为淘宝
nrm use npm ---- 切换镜像源为npm主站
nrm test ---- 测试镜像源的速度
```
### 解决报错
使用 nrm 的时候(执行`nrm ls`命令的时候),会有报错,解决方案两种:
- 按照报错提示,找到有错误的文件(cli.js),把第9行注释即可。
- 重新安装包 `npm install -g nrm open@8.4.2`
上述是nrm包本身的错误。
还有一种报错,当用nrm的时候,提示如下:

解决方案是:
- `管理员`方式,打开命令行(powershell)窗口
- 执行 `set-ExecutionPolicy RemoteSigned;`
- 在出现的选项中,输入 `A`,回车。即可。
## 差别
项目包的使用方式,是引入到 js 代码中,使用。

全局包的使用方式,是在终端窗口中,使用。

# [了解]自定义模块
## 语法实现
任何一个js文件,都是自定义模块。
我们要研究的是导入自定义模块,会得到什么???
准备两个文件,测试一下:
03-导出.js
```js
// 一个模块,默认导出的就是 空对象
// 使用如下固定语法,导出内容
module.exports = 导出的内容
module.exports = 123 // 导出123
module.exports = { name: 'zs', age: 20 } // 导出对象
```
04-导入.js
```js
// 导入细节:
// 1. ./ 必须得加
// 2. .js 可以省略
const aaa = require('./03-导出.js')
console.log(aaa) // { name: 'zs', age: 20 }
```
## 为什么需要自定义模块
- 为了做封装操作
- 为发布自己的包做准备

## module.exports 和 exports 的区别
- 在一个模块中,**module.exports 才真正的表示导出的内容**,默认指向一个空对象
- exports 指向 module.exports 【`let exports = module.exports`】
- 如果**给 exports 一个 一个的添加属性**,则属性添加给了导出的对象中,**没有问题**。
- 如果 给 exports 直接赋一个新的值,则 exports 和 modules.exports 就是两个不同的值了。
- 实际开发中,直接使用 module.exports 就可以了。
# [了解]发布一个包
## 注册npm账号
进入 npmjs.com 网站,点击右上角的 sign up 注册。
其他略,看视频
> 如果注册不上,换个时间注册。
## 开发自己的包
```
独立的文件夹
| - index.js 把你的功能写到这里,并且导出
| - Readme.md 包的说明文档(你需要给使用者提供一个文档)
| - package.json 包的配置文件(版本是什么、包名是什么、入口文件是什么......)
```
index.js代码:
```js
function aa() {
console.log(111)
}
function bb() {
console.log(222)
}
module.exports = { aa, bb }
```
Readme.md代码:
````markdown
## 安装
```
npm i sy155
```
## 使用
```js
const sy155 = require('sy155')
sy155.aa() // 111
sy155.bb() // 222
```
````
package.json (执行 npm init 得来):
```json
{
"name": "sy155",
"version": "1.0.0",
"description": "```\r npm i sy155\r ```",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "laotang",
"license": "ISC"
}
```
## 发布和更新
1. 切换镜像源 为 npm 主站(`nrm use npm`)。因为发布包,不能发布到淘宝。
2. 终端中,注册路径是当前项目。执行 `npm login` 登录
1. 输入账号
2. 密码
3. 邮箱
4. 验证码
3. 执行 `npm publish` 发布包
后续如果要更新包,步骤是:
1. 更新你的代码
2. 更新你的文档
3. 关键的是,必须提升版本号,比如之前发布的是 1.0.0 版本,修改代码后,版本就得是 1.0.1 或更高
4. 执行 `npm publish` 更新你的包
# [面试]require加载机制
require() 是Node环境内置的一个函数。它的作用就是导入模块。
- 可以导入内置模块,比如 fs、path
- 可以导入第三方模块,比如 dayjs、moment
- 可以导入自定义模块,比如 ./03-导出
**require导入特点**:
- 首先,无论导入什么模块,导入之后,都会把得到的结果缓存(保存到内存中,方便下次使用)
- 导入时写路径了(比如 `./abc`) ---------- 说明导入的是自定义模块
- 优先导入同名文件,也就是导入叫做 abc 的文件
- 则导入 abc.js 文件
- 则导入 abc.json 文件
- 则报错,Cannot find module './abc' ,找不到模块 abc
- 导入时没有写路径(直接写的模块名) ------ 说明导入的是内置模块或第三方模块
- 优先导入内置模块
- 没有内置模块,则导入第三方模块
- 优先从当前文件夹的node_modules里面找
- 再从当前文件夹的上层文件夹里的node_modules里面找
- 再从上层的上层的node_modules里面找
- ....................... 一直找到根路径
- 如果还没有 找到,则报错 Cannot find module 'dayjs' ,找不到模块 dayjs
# [了解]package.json文件
package.json 在 执行 `npm init` 之后,自动生成。
它是项目的配置文件。
- name 表示包的名字
- 发布自己的包,名字不能和已发布的包重名;
- 平时做项目name随便写
- 不能和你要安装的包名重名,比如不能叫做 dayjs、axios、echarts
- version 表示版本
- 发布自己的包的时候,版本随便
- 更新包的时候,版本**必须**提升一点
- description 包的描述信息
- 平时开发项目没有用
- 发布包的时候,可以简单的描述一下包的功能,会显示到搜索框的下面(一行小字)
- main 包的入口文件
- 默认就是index.js
- 当别人通过require加载我们的包的时候,加载的就是 main 指定的文件
- **scripts** 存一下命令的简写
- "简写": "完整的命令或包的名字"
- "a": "git init"
- 当运行 a 命令的时候,就如同运行了 git init 命令
- npm run a 就是运行 a 命令
- **dependencies** 这里记录了项目的依赖
- 记录了你安装了哪些包。通过这个,你就可以知道安装了哪些个包
- 执行 `npm i` ,会把 dependencies 记录的包重新安装回来
- **devDependencies** 这里记录了项目的开发依赖
- 执行 `npm i` ,会把 devDependencies 记录的包重新安装回来
# [重点]ES6模块化语法
## 什么是模块化设计
把一个大件(电脑、手机、桌子)可以拆分成若干零件(模块),而且还能组装到一起。这就是模块化设计。
编程中,每个功能(发请求、日期处理.....)都封装成一个小模块,用的时候,按需导入使用。
优点:
- 更利于维护(比如,项目需要对登录模块升级,则不会影响其他模块)
- 更好的复用性(比如有一个公共的函数,封装起来。其他所有JS文件都能使用这个函数)
## 模块化方案
能够实现,在JS中导入另外的JS。
- AMD方案 (只能在浏览器端使用)
- CMD方案 (只能在浏览器端使用)
- **CommonJS方案** (只能在Node环境中使用)Node默认使用的导入导出,就是CommonJS方案。
- 使用 module.exports 导出内容
- 使用 require 导入内容
- ES6(2015年发布)中,官方终于给出了官方的导入导出方案。叫做 "ES Module",ES模块化
- 毕竟是官方的
- 在浏览器和Node环境中都可以使用
- 使用 export 导出内容;
- 使用 import 导入内容
## 配置一下
配置一下,才能使用ES6模块化语法。
在Node环境中,默认使用的是 CommonJS 语法。
- 要么使用 ES 模块化语法
- 要么使用 CommonJS 语法
**二者不能混用**。
**具体配置**:初始化(npm init),在package.json中,增加 `"type": "module"`
## ES6模块化语法
### [关键]默认导入导出
导出语法:
```js
export default 导出的内容
```
导入语法:
```js
import 变量 from '模块路径'
```
细节:
1. 一个文件最多只能有一次默认导出
2. **导入语法,同样可以导入内置模块 和 第三方模块,比如导入 fs、dayjs、axios等等**
### [关键]按需导入导出
导出语法:
```js
需要导出什么,就在前面加 export 关键字即可
export let sex = '男' // 需要导出它
let age = 20 // 不需要导出,那就不加export
export let obj = { height: 190, weight: 80 } // 需要导出它
```
导入语法:
```js
需要导入什么,就导入什么
import { 变量, 变量, .... } from '模块路径' // 变量名必须和导出的变量名 同名
import { 变量, 变量 as 其他名, .... } from '模块路径' // 有冲突,用as定义其他名
```
### 导入资源文件
像 css、less、图片等等,叫做资源文件。
也可以使用这种语法导入资源文件。
```js
import './abc.css'
```
> 这个语法,在webpack中才可以使用。
### 一次性导入全部
如果一个文件,既有默认导出、又有按需导出;能不能用一行代码,把这些内容全部导入?
答案:有这个语法,可以的。
```js
import * as obj from '模块路径'
console.log(obj)
// 得到如下结果
{
age: 20,
name: 'zs',
sex: '男',
default: { name: 'zs', age: 20, sex: '男' }
}
```
# [理解]webpack配置
## 目标
理解webpack是什么,做了什么?
- 打包 (把 src 中的所有文件 ,融合到一起,放到dist文件夹里面)
理解webpack中的插件有什么用?
理解loader加载器有什么用?
**知道,记住,项目如何运行,如何访问**。
## 后面的开发模式
和前面不一样了。
感觉很高大上。
## 演示一下真正的开发模式
我们拿做图表为例。
- 新建一个文件夹,比如叫做 webpack-demo
- 执行 npm init 初始化
- 执行 npm i echarts 安装 echarts
- ① 在 webpack-demo 中,新建 src 源代码目录
② 在 webpack-demo 中,新建 public 静态资源目录
③ src 目录中创建 index.js
④ public 目录中创建 index.html
⑤ index.html 中创建一个具有宽高的div,**id="main"**(准备放图表)
⑥ index.js 中,通过 ES6 模块化的方式导入echarts,实现一个简单的图表(参考echarts官方网站)
```js
import * as echarts from 'echarts';
let myChart = echarts.init(document.querySelector('#main'));
let option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}
]
};
myChart.setOption(option);
```
上述步骤结束后,还不能直接使用。
还需要安装配置webpack:
1. 安装包:npm i webpack@5.73.0 webpack-cli@4.10.0 -D
2. package.json中,scripts节点中,新增 "build": "webpack"
3. 终端中:执行 npm run build 即可打包
打包结束,我们得到 dist/main.js。index.html 引入 main.js 。
浏览器此时可以预览页面了。
## 配置webpack
在项目 根目录,创建 webpack.config.js ,它就是webpack的配置文件。
```js
// 这个webpack的配置文件 webpack.config.js vue.config.js
module.exports = {
// 把所有的配置都放到这个对象里面
mode: 'development' // development(开发) production(生产)
}
```
上述配置了打包模式:
- development,开发模式。这种模式下,打包速度非常快,适合在开发阶段使用
- production,生成模式,这种模式下,生成的main.js体积非常小,适合项目发布阶段使用。
下面配置打包的入口和出口:
- 默认的入口 src/index.js
- 默认的出口 dist/main.js
当然,这两个都可以修改,修改方式如下:
```js
// 这个webpack的配置文件 webpack.config.js vue.config.js
const { join } = require('path')
module.exports = {
// 把所有的配置都放到这个对象里面
mode: 'development', // development(开发) production(生产)
entry: './src/index.js', // 打包的入口,默认是 src/index.js
output: {
path: join(__dirname, 'dist'), // 目录必须用绝对路径
filename: 'bundle.js'
}
}
```
重新运行 npm run build 打包,即可得到新的出口文件 bundle.js 。所以 index.html 引入 dist/bundle.js。
## 配置webpack的插件
没有插件,修改了代码,手动打包。也可以,就是比较 low。
有了插件,就可以使打包非常的顺畅。非常的智能。自动打包。
**通过安装和配置第三方的插件,可以拓展 webpack 的能力,从而让 webpack 用起来更方便**。
**下载所需的包**:
```
npm i clean-webpack-plugin@4.0.0 html-webpack-plugin@5.3.2 webpack-dev-server@4.3.1 -D
```
**配置**:webpack.config.js
```js
// 这个webpack的配置文件 webpack.config.js vue.config.js
const { join } = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlPlugin = require('html-webpack-plugin');
module.exports = {
// 把所有的配置都放到这个对象里面
mode: 'development', // development(开发) production(生产)
entry: './src/index.js', // 打包的入口,默认是 src/index.js
output: {
path: join(__dirname, 'dist'), // 目录必须用绝对路径
filename: 'bundle.js'
},
// 下面是配置插件
plugins: [
new CleanWebpackPlugin(),
new HtmlPlugin({
template: join(__dirname, 'public', 'index.html'), // public中,你的html叫什么
filename: 'index.html' // 打包后的html叫什么(这个文件会生成到dist文件夹)
})
],
// 配置自动打包。会创建一个本地服务器,打包后,我们需要使用 localhost:8080 去访问页面
devServer: {
// port: 9000, // 实时打包所用的端口号
open: true // 初次打包完成后,自动打开浏览器
}
}
```
package.json中,scripts位置:
```json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"serve": "webpack serve"
},
```
后续,终端运行 npm run serve
- 运行这个命令,就会创建一个本地服务器
- 我们访问页面,**必须** 使用 localhost:8080 访问
使用自动打包插件之后,会把打包的结果放到内存中,所以在dist文件夹里看不到文件了。
- 如果把 bundle.js 还是放到dist里面,会反复的创建、删除文件,对磁盘不好
- 如果把打包的结果放到内存中,打包的速度会非常快。
> 开发阶段,使用 npm run serve 命令,打包速度快
>
> 项目做完,使用 npm run build 命令,就会在dist文件夹生成结果。
## 配置loader加载器
webpack只能打包js文件。
如果需要打包非JS文件,比如css、image等,就需要loader的帮助。
**安装包**:
```
npm i style-loader@3.3.1 less-loader@11.0.0 less@4.1.2 html-loader@3.1.0 css-loader@6.7.1 cross-env@7.0.3 babel-loader@8.2.5 @babel/core@7.18.2 @babel/plugin-proposal-decorators@7.18.2 @babel/preset-env@7.18.2 -D
```
**配置**:webpack.config.js
```js
// 这个webpack的配置文件 webpack.config.js vue.config.js
const { join } = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlPlugin = require('html-webpack-plugin');
module.exports = {
// 把所有的配置都放到这个对象里面
mode: 'development', // development(开发) production(生产)
entry: './src/index.js', // 打包的入口,默认是 src/index.js
output: {
path: join(__dirname, 'dist'), // 目录必须用绝对路径
filename: 'bundle.js'
},
// 下面是配置插件
plugins: [
new CleanWebpackPlugin(),
new HtmlPlugin({
template: join(__dirname, 'public', 'index.html'), // public中,你的html叫什么
filename: 'index.html' // 打包后的html叫什么(这个文件会生成到dist文件夹)
})
],
// 配置自动打包。会创建一个本地服务器,打包后,我们需要使用 localhost:8080 去访问页面
devServer: {
// port: 9000, // 实时打包所用的端口号
open: true // 初次打包完成后,自动打开浏览器
},
// 下面配置loader
module: {
rules: [
// 处理css文件
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
// 处理less文件
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
// 处理html中img标签引入的图片
{ test: /\.html$/, use: 'html-loader' },
// 处理图片资源
{
test: /\.(jpg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 12000, // 图片超过这个大小,使用原图片,否则使用base64字符串
}
}
}
]
}
}
```
**测试**:
- 准备一个demo.css 、abc.less、准备3个图片
- 在index.js中,引入 css和less (`import './demo.css'`),看看页面有没有样式
- 在 index.html 中,准备3个div
- 使用 img 的 src 引入一个图片
- demo.css 中,找到第2个div,设置高度,设置背景图
- index.js 中,引入图片,然后 div.style.backgroundImage = `url(${pic})`
最后,看到效果。
## 最终的打包
- 在 package.json 中,修改 build命令
- `"build": "webpack --mode production",`
- 这样,运行 build 命令,就会以生产模式去打包
- 在 webpack.config.js 配置文件的 output 节点中,进行如下的配置:
```javascript
output: {
path: join(__dirname, 'dist'),
filename: 'js/bundle.js', // 这里加入 js 文件夹。
assetModuleFilename: 'images/[hash:8][ext]' // 配置文件(图片)的输出路径
},
```
**最终,npm run build 打包结果。最终的产出就是 dist 文件夹**。
## base64格式
base64格式,是一个很长的字符串。
用这个字符串,表示任何文件。比如表示图片。
浏览器可以识别出 base64 格式的图片。
base64图片 和 图片的jpg、png的区别:
- base64字符串,比原图片 大 30% 左右。 ----> 大图片不适合用base64格式
- 使用base64图片,可以减少http请求,加快小图片的渲染。
**结论:小图片,适合使用base64格式;大图片不适合**。
# 总结
重点是 掌握 npm 的使用
- 会初始化、会安装包、会卸载包
重点是 掌握 ES6 的导入导出语法
- 通过 export 导出、通过 import 导入
关于webpack就是理解,因为后面的项目,都会一键生成所有的配置。
- 知道,运行项目,执行 `npm run serve` 命令,然后通过 localhost:8080 访问项目。