一.AJAX阶段
AJAX是异步的JavaScript和XML(Asynchronous JavaScript And XML)。
XML可扩展标记语言,被设计用来传输和存储数据,现已经被JSON取代了。
简单点说,就是使用XMLHttpRequest对象与服务器通信。
通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据
优点 :
(1)可以无需刷新页面而与服务器端进行通信
(2)允许你根据用户时间来更新部分页面内容
缺点:
(1)没有浏览历史,不能回退
(2)存在跨域问题(同源)
(3)SEO不友好
请求报文
响应报文
1.axios
1.1 axios入门案例
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<p class="my-p"></p>
<script>
axios({
url: 'http://hmajax.itheima.net/api/province'
}).then(result=>{
document.querySelector('.my-p').innerHTML=result.data.list.join('<br>');
})
</script>
1.2 url:协议、域名、资源路径
url查询参数:语法:http://xxx.com/xxx/xxx?参数名1=值1&参数名2=值2
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<p class="my-p"></p>
<script>
axios({
url: 'http://hmajax.itheima.net/api/area',
params:{
pname: '江西省',
cname: '九江市'
}
}).then(result=>{
document.querySelector('.my-p').innerHTML=result.data.list.join('<br>');
})
</script>
常用请求方法和数据提交
GET:获取数据
POST:提交数据
PUT:修改数据
DELETE:删除数据
PATCH:修改数据(部分)
1.3 数据提交
场景:当数据需要在服务器上保存时
注册数据提交
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<button>注册</button>
<script>
document.querySelector('button').addEventListener('click',()=>{
axios({
url: 'http://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: 'hekdkfksd',
password: '23145325132'
}
}).then(result=>{
console.log(result);
})
})
</script>
1.4 axios的核心配置:
url,data,method,params
1.4.1 GET
axios({
url: 'XXXX'.
method: 'GET', //可以省略
params: { //携带查询参数
参数名: 值
}
})
1.4.2POST
axios({
url: 'XXXX'.
method: 'POST',
data: { /
参数名: 值
}
})
1.5 axios错误处理
语法:在then方法的后面,通过点语法调用catch方法,传入回调函数并定义形参
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<button>注册</button>
<script>
document.querySelector('button').addEventListener('click',()=>{
axios({
url: 'http://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: 'hekdkfksd',
password: '23145325132'
}
}).then(result=>{
console.log(result);
}).catch(error => { //错误处理
console.log(error);
alert(error.response.data.message);
})
})
</script>
1.6 HTTP协议
HTTP协议:规定了浏览器发送及服务器返回内容的格式
1.6.1 请求报文
请求报文的组成部分有:
1.请求行:请求方法,URL,协议
2.请求头:以键值对的格式携带的附加信息
3.请求体:发送的资源
可以通过查看请求报文来进行排错
请求头
请求体:
1.6.2 响应报文
响应报文的组成:
1.响应行(状态行):协议,HTTP响应状态码,状态信息
2.响应头:以键值对的格式携带的附加信息,比如:Content-Type
3.响应体:返回的资源
状态码:
1XX:信息
2XX: 成功
3XX:重定向信息
4XX:客户端错误
5XX: 服务端错误
比如:404(服务端找不到资源)
响应头:
响应体:
1.7接口文档
由后端提供的描述接口的文档
FD
登录:
Body参数=>data里面的参数
application/json表明传的是json字符串,但是在data中的键值对会自动转换成json字符串
登录案例
<input type="text" class="username"> <br>
<input type="password" class="password"><br>
<button>登录</button>
<script>
document.querySelector('button').addEventListener('click',
()=>{
username = document.querySelector('.username').value;
password = document.querySelector('.password').value;
if(username.length<8){
alert('用户名需不小于8位');
return;
}
if(password.length<6){
alert('密码需不小于6位');
return;
}
axios({
url: 'https://hmajax.itheima.net/api/login',
method: 'post',
data: {
username,
password
}
}).then(response=>{
console.log(response.data.message);
}).catch(error=>{
console.log(error.response.data.message);
})
})
</script>
2.AJAX原理
XMLHttpRequest(XHR)对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL。这允许网页在不影响用户操作的情况下,更新页面的局部内容。
axios内部采用XMLHttpRequest与服务器交互
2.1XMLHttpRequest对象实例
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
//1.创建xhr对象
const xhr = new XMLHttpRequest();
//2.调用open方法,设置url和请求方法
xhr.open('get','https://hmajax.itheima.net/api/province');
//3.监听loadend事件,接收结果
xhr.addEventListener('loadend',()=>{
console.log(xhr.response)
//将JSON字符串转化成JS对象
const data=JSON.parse(xhr.response)
console.log(data.list);
})
//调用send方法,发送请求
xhr.send()
</script>
XMLHttprRequest查询参数: xhr.open('get','https://hmajax.itheima.net/api/city?pname=河北省');
2.2XMLHttpRequest数据提交
请求头设置Content-Type:application/json
请求体携带JSON字符串
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
const xhr = new XMLHttpRequest();
xhr.open('post','https://hmajax.itheima.net/api/register');
xhr.addEventListener('loadend',()=>{
console.log(xhr.response);
})
//设置请求头
xhr.setRequestHeader('Content-Type','application/json');
const userObj = {
username: 'hk666666',
password: '123456'
}
//将对象转换成JSON字符串
const userStr = JSON.stringify(userObj);
xhr.send(userStr)
</script>
2.3promise
表示(管理)一个异步操作最终状态和结果值的对象
优点:
1.逻辑更清晰
2.了解axios函数内部运作机制
3.能解决回调函地狱问题
resolve(value):
当异步操作成功完成时,调用 resolve 函数,并传递操作的结果或值作为参数。这会将 Promise 对象的状态从 “Pending”(进行中)改变为 “Fulfilled”(已成功)状态。在 .then() 方法中注册的回调函数将会被执行,并且可以访问到传递给 resolve 函数的值。
reject(reason):
当异步操作遇到错误或失败时,调用 reject 函数,并传递一个错误原因作为参数。这会将 Promise 对象的状态从 “Pending”(进行中)改变为 “Rejected”(已失败)状态。在 .catch() 方法中注册的回调函数将会被执行,并且可以访问到传递给 reject 函数的错误原因。
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
//1.创建Promise对象
const p = new Promise((resolve,reject) => {
//2.执行异步代码
setTimeout(()=>{
// resolve('模拟AJAX请求成功')
reject(new Error('模拟AJAX请求失败'))
},2000)
})
//3.获取结果
p.then(result=>{
console.log(result);
}).catch(error=>{
console.log(error)
})
</script>
也可以都放到then中:
<script>
//1.创建Promise对象
const p = new Promise((resolve, reject) => {
//2.执行异步代码
setTimeout(() => {
// resolve('模拟AJAX请求成功')
reject(new Error('模拟AJAX请求失败'))
}, 2000)
})
//3.获取结果
p.then(result => {
console.log(result);
},error => {
console.log(error)
})
</script>
同步代码和异步代码
同步代码:逐行执行,需原地等待结果后,才继续向下执行
异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发一个回调函数
回调函数地狱:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
缺点:可读性差,异常无法捕获,耦合性严重
2.4async函数和await
async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需可以地链式调用promise
async 的全称是 Asynchronous,发音是 /əˈsɪŋkrənəs/
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<div class="province"></div>
<div class="city"></div>
<div class="area"></div>
<script>
//函数前加async
async function getData(){
//try包裹可能产生错误的代码
try{
//在promise对象前加await
const pObj=await axios({url:'https://hmajax.itheima.net/api/province'})
pname = pObj.data.list[0]
const cObj=await axios({url:'https://hmajax.itheima.net/api/city',params:{
pname}})
cname = cObj.data.list[0]
const aObj=await axios({url:'https://hmajax.itheima.net/api/area',params:{
pname,cname
}})
aname = aObj.data.list[0]
document.querySelector('.province').innerHTML=pname
document.querySelector('.city').innerHTML=cname
document.querySelector('.area').innerHTML=aname
}catch(error){
//接着调用catch块,接收错误信息
console.dir(error)
}
}
getData()
</script>
2.5事件循环
执行代码和收集异步任务的模型,在调用栈空闲,反复调用任务队列里回调函数的执行机制,就叫事件循环
原因:JS是单线程的,为了不阻塞JS引擎,设计执行代码的模型
执行流程:
1.执行同步代码,遇到异步代码交给宿主浏览器环境执行
2.异步有了结果后,把回调函数放入任务队列排队
3.当调用栈空闲时,反复调用任务队列里的回调函数
宏任务与微任务
微任务队列比宏任务队列更先执行
p.then()本身是同步的,但里面的回调函数是异步的,且只有等p有了成功的状态,状态改变之后才会将回调函数推到微任务队列中去
p.then(result=>{
console.log(result);
})
执行流程:
(1)执行第一个script脚本事件宏任务里面的同步代码
(2)遇到宏任务/微任务交给宿主环境,有结果回调函数进入对应队列
(3)当执行栈空闲时,先清空微任务队列,再执行下一个宏任务,从1再来
Promise.all静态方法
Promise.all 是一个静态方法,它接收一个可迭代的对象(比如数组)作为参数,并返回一个新的 Promise 对象。这个新的 Promise 对象在传入的所有 Promise 对象都已经解决(resolved)时才会解决。如果传入的任何一个 Promise 被拒绝(rejected),那么 Promise.all 返回的 Promise 对象会立即被拒绝,其拒绝原因是第一个被拒绝的 Promise 的拒绝原因。
二 .Node.js
Node.js是一个跨平台JS运行环境,使开发者可以搭建服务器端的JS应用程序
作用:使用Node.js编写服务器端程序
(1)编写数据接口,提供网页资源浏览功能等等
(2)前端工程化:为后续学习Vue和React等框架做铺垫
**前端工程化:**开发项目直到上线,过程中集成的所有工具和技术,有打包工具、格式化工具、压缩工具、转换工具、脚手架工具等等
Node.js为何能执行JS:
首先:浏览器能执行JS代码,依靠的是内核中的V8引擎(c++程序)
其次:Node.js是基于Chrome V8引擎进行封装
注意: Node.js环境没有DOM和BOM,取而代之的是fs和path
Node.js运行js文件
fs模块-读写文件
const fs = require('fs')
fs.writeFile('./test.txt','Hello World!',(err)=>{
if(err) console.log(err)
else console.log('写入成功');
})
fs.readFile('./test.txt',(err,data)=>{
if(err) console.log(err)
//这里返回的data是十六进制的序列
else console.log(data)
//通过toString()方法转成字符串
// else console.log(data.toString())
})
path模块-路径处理
在Node.js代码中,相对路径是根据终端所在路径来查找的
建议:使用绝对路径
说明: path_test.js在path_test文件夹下,需要访问的test.txt与path_test文件夹同级
const fs = require('fs')
const path = require('path')
//__dirname的输出结果为 C:\Users\12345\Desktop\js\path_test
//console.log(__dirname);
fs.readFile(path.join(__dirname,'../test.txt'),(err,data)=>{
if(err) console.log(err)
else console.log(data.toString())
})
压缩前端html
步骤:
(1)读取源html文件内容
(2)正则替换字符串
(3)写入到新的html文件中
去掉html中的\t\n
const { log } = require('console');
const fs = require('fs')
const path = require('path')
fs.readFile(path.join(__dirname,'../index.html'),(err,data)=>{
if(err) console.log(err);
else{
const htmlStr = data.toString();
const resultStr = htmlStr.replace(/[\r\n]/g,'')
console.log(resultStr);
fs.writeFile(path.join(__dirname,'../result.html'),resultStr,err=>{
if(err) console.log(err);
else console.log('写入成功');
})
}
})
编写Web服务程序
端口号:标记服务器里不同功能的服务程序
范围:0-65535之间的任意整数
0-1023和一些特定端口号被占用,我们自己编写服务程序时避开使用
http协议默认访问80端口
web服务程序:用于提供网上信息浏览功能
http模块-创建Web服务
//加载http模块,创建Web服务对象
const http = require('http')
const server = http.createServer()
//监听request请求事件,设置响应头和响应体
server.on('request',(req,res)=>{
//设置响应头-内容类型-普通文本以及编码格式
res.setHeader('Content-Type','text/plain;charset=utf-8')
//设置响应体内容,结束本次请求与响应
res.end('欢迎使用node.js创建的Web服务')
})
//配置端口号并启动Web服务
server.listen(3000,()=>{
console.log('Web服务已启动');
})
web服务程序提供html网页案例
const fs = require('fs')
const path = require('path')
const http = require('http')
const server = http.createServer()
//监听request请求事件,设置响应头和响应体
server.on('request',(req,res)=>{
if(req.url==='/index.html'){
fs.readFile(path.join(__dirname,'index.html'),(err,data)=>{
if(err) console.log(err)
else{
res.setHeader('Content-Type','text/html;charset=utf-8')
res.end(data.toString())
}
})
}
else{
res.setHeader('Content-Type','text/html;charset=utf-8')
res.end('访问的数据不存在')
}
})
//配置端口号并启动Web服务
server.listen(3000,()=>{
console.log('Web服务已启动');
})
Node.js模块化
在Node.js中,每个文件都被视为一个单独的模块
项目是由很多个模块文件组成的
使用:需要标准语法导出和导入进行使用
CommonJS语法-导入导出模块语法:
被导出模块:
// baseURL和getArraySum是需要对外暴露的两个属性
const baseURL='http://hmajax.itheima.net'
const getArraySum = arr => arr.reduce((sum,item)=> sum+=item,0)
//使用基于CommonJS标准语法,封装属性和方法并导出
module.exports = {
url: baseURL,
arraySum: getArraySum
}
导入模块:
const obj = require('./utils.js')
const result = obj.arraySum([2,3,45,52,23])
console.log(result);
ECMAScript标准-默认导出和导入
(1)默认被导出模块:
// baseURL和getArraySum是需要对外暴露的两个属性
const baseURL='http://hmajax.itheima.net'
const getArraySum = arr => arr.reduce((sum,item)=> sum+=item,0)
//默认导出
export default {
url: baseURL,
arraySum: getArraySum
}
(2)package.json
{
"type": "module"
}
(3)需导入模块
import obj from './utils.js'
console.log(obj)
ECMAScript标准-命名导出和默认导出
如何选择:
按需加载,使用命名导出和导入
全部加载:使用默认导出和导入
utils.js:
export const baseURL='http://hmajax.itheima.net'
export const getArraySum = arr => arr.reduce((sum,item)=> sum+=item,0)
01.js:
import {baseURL,getArraySum} from './utils.js'
console.log(baseURL,getArraySum)
包的概念
包:将模块、代码、其他资料聚合成一个文件夹
包分类:
项目包:主要用于编写项目和业务逻辑
软件包:封装工具和方法进行使用
要求:根目录中,必须有package.json文件(记录包的清单信息)
注意:导入软件包时,引入的默认是index.js模块文件/main属性指定的模块文件
目录结构:
(1)04文件夹下有utils文件夹和server.js文件
(2)utils文件夹下有lib文件夹和index.js
(3)lib文件夹有最终的arr.js和str.js文件
流程:
(1)在index.js中将arr.js和str.js导入,最后统一导出所有函数
(2)server.js文件导入utils软件包,使用里面封装的工具函数
//arr.js
const getArraySum = arr => arr.reduce((sum,item)=> sum+=item,0)
module.exports={
getArraySum
}
//str.js
const checkUserName = username => {
return username.length >=8
}
const checkPassWord = password => {
return password.length >=6
}
module.exports = {
checkUser: checkUserName,
checkPwd: checkPassWord
}
//index.js
//本文件是tuils工具包的唯一出口
//作用:把所有工具模块方法集中起来,统一向外暴露
const {getArraySum} = require('./lib/arr.js')
const {checkUser,checkPwd} = require('./lib/str.js')
//统一导出所有函数
module.exports = {
getArraySum,
checkUser,
checkPwd
}
//server.js
// 目标:导入utils软件包,使用里面封装的工具函数
const obj = require('./utils')
console.log(obj)
console.log(obj.getArraySum([23,532,234]))
npm-软件包管理器
npm是Node.js标准的软件包管理器
使用npm下载dayjs软件包来格式化日期时间
步骤:
(1)初始化项目清单文件,命令:npm init -y
(2)下载软件包到当前项目,命令:npm i dayjs
(3)使用软件包
//server.js文件:
//使用软件包
const dayjs = require('dayjs')
console.log(dayjs().format('YYYY-MM-DD'));
npm安装所有依赖
场景:当从网上下载了一个项目,项目中不包含node_modules所以不能运行。
之所以不包含node_modules是 因为自己用npm下载依赖比磁盘传递拷贝要快得多
解决办法:项目终端输入命令: npm i 下载package.json中记录的所有软件包
npm-全局软件包nodemon
本地软件包:当前项目内使用,封装属性和方法,存在与node_modules
全局软件包:本机所有项目使用,封装命令和工具,存在与系统设置的位置
nodemon作用:替代node命令,检测代码更改,自动重启程序
nodemon的安装:npm i nodemon -g
三.Webpack
Webpack中文文档
webpack是一个用于现代JS应用程序的静态模块打包工具。
静态模块指的是编写代码过程中的html、css、js图片等固定内容的文件
打包:把静态模块内容,压缩,整合,转译等(前端工程化)
webpack体验
(1)npm init -y 初始化package.json文件
(2)在package.json中配置webpack
(3)编写check.js
export const checkPhone = phone => phone.length === 11
export const checkCode = code => code.length === 6
(4)npm i webpack webpack-cli --save-dev (准备webpack打包环境)
(5)index.js中导入check.js里封装的属性和函数
import {checkPhone,checkCode} from './utils/check.js'
console.log(checkPhone('1347329324'))
console.log(checkCode('234234'));
(6)运行自定义命令打包观察效果(npm run 自定义命令),得到dist文件夹
修改Webpack打包入口和出口
Webpack打包入口默认是src/index.js 出口默认的是dist/main.js
修改步骤:
(1)在项目根目录下新建webpack.config.js配置文件
(2)导出配置对象,配置入口、出口文件路径
const path = require('path')
module.exports = {
//入口
entry: path.resolve(__dirname,'src/login/index.js'),
//出口
output: {
path: path.resolve(__dirname,'dist'),
filename: './login/index.js',
clean: true //生成打包后内容之前,清空输出目录
}
}
(3)使用 npm run 自定义命令 打包观察
Webpack自动生成html文件
(1)下载html-webpack-plugin本地软件包
(2)配置webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
//入口
entry: path.resolve(__dirname,'src/login/index.js'),
//出口
output: {
path: path.resolve(__dirname,'dist'),
filename: './login/index.js',
clean: true //生成打包后内容之前,清空输出目录
},
plugins: [
new HtmlWebpackPlugin({
//模版文件
template: path.resolve(__dirname,'./public/login.html'),
filename: path.resolve(__dirname,'dist/login/index.html')
})
]
}
(3)重新打包观察
webpack打包css代码
使用css-loader、style-loader来完成
(1)准备css代码,并引入到js中
(2)下载css-loader和style-loader本地软件包
(3)配置webpack.config.js,让webpack拥有该加载器功能
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
(4)打包观察效果
优化-提取css代码
使用mini-css-extract-plugin来提取css代码
style-loader和mini-css-extract-plugin不能一起用
(1)下载mini-css-extract-plugin本地软件包
(2)配置webpack.config.js让webpack拥有该插件功能
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};
(3)打包后观察效果
优化-压缩过程
问题:css代码提取后没有压缩
解决:使用css-minimizer-webpack-plugin插件
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
`...`,
new CssMinimizerPlugin(),
],
},
};
webpack打包less代码
加载器less-loader:把less代码编译为css代码
(1)新建less代码并引入到src/login/index.js中
(2)下载less和less-loader本地软件包
npm install less less-loader --save-dev
(3)配置webpack.config.js
{
test: /\.less$/i,
use: [
// compiles Less to CSS
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
],
},
webpack打包图片
资源模块:webpack5内置资源模块(字体、图片等)打包,无需额外loader
注意: 判断临界值默认为8KB,当大于8KB时,发送一个单独的文件并导出URL地址,
当小于8KB时,导出一个data URI(base64字符串)
步骤:
(1)配置webpack.config.js让Webpack拥有打包图片功能
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset,
generator: {
filename: 'assets/[hash][ext][query]'
}
}
]
}
};
优化-CDN使用
CDN定义:内容分发网络,指的是一组分布在各个地区的服务器
作用:把静态资源文件、第三方库放在CDN网络中各个服务器中,供用户就近请求获取
需求:开发模式使用本地第三方库,生产模式下使用CDN加载引入
webpack搭建开发环境
问题:之前改代码,需重新打包才能运行查看,效率低
开发环境:配置webpack-dev-server快速开发应用程序
作用:启动web服务,自动检测代码变化,热更新到网页