# 框架前置课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环境中正常运行。 ![image-20230503110328615](imgs/image-20230503110328615.png) 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的时候,提示如下: ![image-20230505165000410](imgs/image-20230505165000410.png) 解决方案是: - `管理员`方式,打开命令行(powershell)窗口 - 执行 `set-ExecutionPolicy RemoteSigned;` - 在出现的选项中,输入 `A`,回车。即可。 ## 差别 项目包的使用方式,是引入到 js 代码中,使用。 ![image-20230505150802270](imgs/image-20230505150802270.png) 全局包的使用方式,是在终端窗口中,使用。 ![image-20230505150851864](imgs/image-20230505150851864.png) # [了解]自定义模块 ## 语法实现 任何一个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 } ``` ## 为什么需要自定义模块 - 为了做封装操作 - 为发布自己的包做准备 ![image-20230505155708855](imgs/image-20230505155708855.png) ## 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 访问项目。