Ajax 笔记(四)—— Ajax 进阶

笔记目录

  • 4. Ajax 进阶
    • 4.1 同步代码和异步代码
    • 4.2 回调函数地狱
      • 4.2.1 解决方法一:Promise 链式调用
      • 4.2.2 解决方法二:async 函数和 await
    • 4.3 Promise.all 静态方法
    • 4.4 事件循环
      • 4.4.1 事件循环
      • 4.4.2 宏任务与微任务
    • 4.5 案例
      • 4.5.1 案例一-商品分类
      • 4.5.2 案例二-学习反馈


Ajax 笔记:

Ajax 笔记(一)—— Ajax 入门

Ajax 笔记(二)—— Ajax 案例

Ajax 笔记(三)—— Ajax 原理

Ajax 笔记(四)—— Ajax 进阶


Ajax 笔记接口文档:https://apifox.com/apidoc/shared-fa9274ac-362e-4905-806b-6135df6aa90e/doc-842135


4. Ajax 进阶

4.1 同步代码和异步代码

JavaScript 是单线程的语言,意味着它只有一个主线程用来执行代码。这个特点决定了 JavaScript 在同一时间只能处理一个任务,防止了多线程带来的竞态条件和死锁等问题。随着 HTML5 到来也支持了多线程webWorker,但也是不允许操作 DOM 。

  1. 同步代码:逐行执行,需原地等待结果后,才继续向下执行

  2. 异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发回调函数传递结果,比如:setTimeout / setInterval,事件,Ajax

4.2 回调函数地狱

  1. 概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
  2. 缺点:可读性差,异常无法捕获,耦合性严重

代码示例:

// 需求:展示默认第一个省,第一个城市,第一个地区在下拉菜单中
axios({ url: 'http://hmajax.itheima.net/api/province' }).then(result => {const pname = result.data.list[0]document.querySelector('.province').innerHTML = pname// 获取第一个省份默认下属的第一个城市名字axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } }).then(result => {const cname = result.data.list[0]document.querySelector('.city').innerHTML = cname// 获取第一个城市默认下属第一个地区名字axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } }).then(result => {document.querySelector('.area').innerHTML = result.data.list[0]})})
})

4.2.1 解决方法一:Promise 链式调用

  1. 依靠 then() 方法会返回一个新生成的 Promise 对象特性,继串联下一环任务,直到结束。then() 回调函数中的返回值,会影响新生成的 Promise 对象最终状态和结果。

代码示例:

/*** 目标:掌握Promise的链式调用* 需求:把省市的嵌套结构,改成链式调用的线性结构
*/
// 1. 创建Promise对象-模拟请求省份名字
const p = new Promise((resolve, reject) => {setTimeout(() => {resolve('北京市')}, 2000)
})// 2. 获取省份名字
const p2 = p.then(result => {console.log(result)// 3. 创建Promise对象-模拟请求城市名字// return Promise对象最终状态和结果,影响到新的Promise对象return new Promise((resolve, reject) => {setTimeout(() => {resolve(result + '--- 北京')}, 2000)})
})// 4. 获取城市名字
p2.then(result => {console.log(result)
})// then()原地的结果是一个新的Promise对象
console.log(p2 === p)
  1. 利用 Promise 链式调用解决回调地狱
/*** 目标:把回调函数嵌套代码,改成Promise链式调用结构* 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
*/
let pname = ''
// 1. 得到-获取省份Promise对象
axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {pname = result.data.list[0]document.querySelector('.province').innerHTML = pname// 2. 得到-获取城市Promise对象return axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})
}).then(result => {const cname = result.data.list[0]document.querySelector('.city').innerHTML = cname// 3. 得到-获取地区Promise对象return axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})
}).then(result => {console.log(result)const areaName = result.data.list[0]document.querySelector('.area').innerHTML = areaName
})

4.2.2 解决方法二:async 函数和 await

在 async 函数内,使用 await 关键字取代 then 函数,等待获取 Promise 对象成功状态的结果值

  1. 利用async 函数和 await 解决回调地狱
/*** 目标:掌握async和await语法,解决回调函数地狱* 概念:在async函数内,使用await关键字,获取Promise对象"成功状态"结果值* 注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果)
*/
// 1. 定义async修饰函数
async function getData() {// 2. await等待Promise对象成功的结果const pObj = await axios({url: 'http://hmajax.itheima.net/api/province'})const pname = pObj.data.list[0]const cObj = await axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})const cname = cObj.data.list[0]const aObj = await axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})const areaName = aObj.data.list[0]document.querySelector('.province').innerHTML = pnamedocument.querySelector('.city').innerHTML = cnamedocument.querySelector('.area').innerHTML = areaName
}getData()
  1. async 函数和 await 捕获错误
try {// 要执行的代码
} catch (error) {// error 接收的是,错误消息// try 里代码,如果有错误,直接进入这里执行
}

改进上述代码:

/*** 目标:async和await_错误捕获
*/
async function getData() {// 1. try包裹可能产生错误的代码try {const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' })const pname = pObj.data.list[0]const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })const cname = cObj.data.list[0]const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } })const areaName = aObj.data.list[0]document.querySelector('.province').innerHTML = pnamedocument.querySelector('.city').innerHTML = cnamedocument.querySelector('.area').innerHTML = areaName} catch (error) {// 2. 接着调用catch块,接收错误信息// 如果try里某行代码报错后,try中剩余的代码不会执行了console.dir(error)}
}getData()

4.3 Promise.all 静态方法

合并多个 Promise 对象并等待所有同时成功的结果,如果有一个报错就会最终为失败状态,当需要同时渲染多个接口数据同时到网页上时使用

const p = Promise.all([Promise对象, Promise对象, ...])
p.then(result => {// result 结果: [Promise对象成功结果, Promise对象成功结果, ...]
}).catch(error => {// 第一个失败的 Promise 对象,抛出的异常对象
})

实例代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Promise的all方法</title>
</head><body><ul class="my-ul"></ul><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>/*** 目标:掌握Promise的all方法作用,和使用场景* 业务:当我需要同一时间显示多个请求的结果时,就要把多请求合并* 例如:默认显示"北京", "上海", "广州", "深圳"的天气在首页查看* code:* 北京-110100* 上海-310100* 广州-440100* 深圳-440300*/// 1. 请求城市天气,得到Promise对象const bjPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '110100' } })const shPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '310100' } })const gzPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440100' } })const szPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440300' } })// 2. 使用Promise.all,合并多个Promise对象const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise])p.then(result => {// 注意:结果数组顺序和合并时顺序是一致console.log(result)const htmlStr = result.map(item => {return `<li>${item.data.data.area} --- ${item.data.data.weather}</li>`}).join('')document.querySelector('.my-ul').innerHTML = htmlStr}).catch(error => {console.dir(error)})</script>
</body></html>

4.4 事件循环

4.4.1 事件循环

  1. 作用:事件循环负责执行代码,收集和处理事件以及执行队列中的子任务
  2. 原因:JavaScript 单线程(某一刻只能执行一行代码),为了让耗时代码不阻塞其他代码运行,设计了事件循环模型
  3. 概念:执行代码和收集异步任务的模型,在调用栈空闲,循环不断地调用任务队列里回调函数的执行机制,就叫事件循环

举例说明:

/*** 目标:阅读并回答执行的顺序结果
*/
console.log(1)
setTimeout(() => {console.log(2)
}, 0)
function myFn() {console.log(3)
}
function ajaxFn() {const xhr = new XMLHttpRequest()xhr.open('GET', 'http://hmajax.itheima.net/api/province')xhr.addEventListener('loadend', () => {console.log(4)})xhr.send()
}
for (let i = 0; i < 1; i++) {console.log(5)
}
ajaxFn()
document.addEventListener('click', () => {console.log(6)
})
myFn()// 结果:1 5 3 2 4 点击一次document就会执行一次打印6

在这里插入图片描述
代码分析:

  1. console.log(1)进入调用栈,然后在控制台打印1
  2. setTimeout是异步代码,交给浏览器,console.log(2) 在 0 s 过后进入任务队列
  3. 然后两个 function 不调用,不执行
  4. for循环放入调用栈执行,打印5
  5. 执行ajaxFnloadend事件异步,交给浏览器
  6. 用户click异步点击事件,交给浏览器,和loadend一样处于监测状态
  7. myFn放入调用栈执行,打印3
  8. 同步代码执行完毕,调用栈清空,然后反复查找任务队列有无需要执行的回调函数
  9. 执行setTimeout,进入调用栈,打印2,出栈
  10. 浏览器中的loadend事件被放入任务队列,然后放入调用栈,执行,打印4
  11. 最后click事件,点击后打印6

4.4.2 宏任务与微任务

  1. 异步任务划分:
  • 宏任务:由浏览器环境执行的异步代码
  • 微任务:由 JS 引擎环境执行的异步代码

宏任务(Macrotasks)

  1. setTimeoutsetInterval:用于创建定时任务,会在指定的时间间隔之后执行回调函数。
  2. DOM 事件:如点击事件、输入事件等。
  3. 网络请求:如 Ajax 请求、fetch 等。
  4. I/O 操作:如文件读写、读取数据库等。
  5. requestAnimationFrame:用于在每次浏览器重绘之前执行的回调。
  6. MessageChannel:一种更底层的异步任务创建方式。
  7. UI 渲染:浏览器会在宏任务执行完成后进行 UI 渲染。

微任务(Microtasks)

  1. Promise 的 resolve 和 reject:当一个 Promise 被 resolved 或 rejected 时,相关的回调会被放入微任务队列。
  2. process.nextTick(Node.js 环境下):类似于 Promise 的微任务,但在 Node.js 环境中使用。
  3. Object.observeMutationObserver:用于监听对象的变化,在变化后会触发回调。
  4. Vue 的 nextTick:Vue 中用于延迟执行 DOM 更新之后的回调。
  5. await 表达式的后续操作:在 async 函数中,await 表达式后的操作会被放入微任务队列。

在这里插入图片描述
JavaScript 执行顺序如下:

  1. 执行同步代码:从上到下逐行执行当前代码文件中的同步代码,将函数调用压入执行栈,遇到异步任务会将其注册,但不会立即执行。

  2. 执行微任务:在每次事件循环中,首先会执行微任务队列中的所有微任务,直到微任务队列为空。这保证了微任务比宏任务更早执行。

  3. 执行宏任务:然后从宏任务队列中取出一个宏任务(通常是先进先出),执行它,可能触发异步操作。

  4. 可能进行 UI 渲染:在宏任务执行完成后,浏览器有机会进行 UI 渲染(如果有需要的话)。

  5. 重复以上步骤:然后事件循环继续,重复执行微任务、宏任务、可能的 UI 渲染等步骤。

实例代码:

/*** 目标:阅读并回答打印的执行顺序
*/
console.log(1)
setTimeout(() => {console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {resolve(3)
})
p.then(res => {console.log(res)
})
console.log(4)// 1 3 5 4 2

代码分析:

  1. console.log(1)进入调用栈,打印1
  2. setTiemout宏任务,交给浏览器,0sconsole.log(2)放入宏任务队列排队
  3. new Promise放入调用栈,执行console.log(3),打印3,用4标记成功,然后出栈
  4. p调用过resolve,处于成功状态,p.then()里面的回调函数是微任务,放入微任务队列排队
  5. console.log(5),进入调用栈打印5,出栈
  6. 调用栈清空,先调度微任务队列的回调函数
  7. 执行微任务console.log(result),打印4
  8. 接着调度宏任务console.log(2),打印2

4.5 案例

4.5.1 案例一-商品分类

/*** 目标:把所有商品分类“同时”渲染到页面上*  1. 获取所有一级分类数据*  2. 遍历id,创建获取二级分类请求*  3. 合并所有二级分类Promise对象*  4. 等待同时成功后,渲染页面
*/
// 1. 获取所有一级分类数据
axios({url: 'http://hmajax.itheima.net/api/category/top'
}).then(result => {console.log(result)// 2. 遍历id,创建获取二级分类请求const secPromiseList = result.data.data.map(item => {return axios({url: 'http://hmajax.itheima.net/api/category/sub',params: {id: item.id // 一级分类id}})})console.log(secPromiseList) // [二级分类请求Promise对象,二级分类请求Promise对象,...]// 3. 合并所有二级分类Promise对象const p = Promise.all(secPromiseList)p.then(result => {console.log(result)// 4. 等待同时成功后,渲染页面const htmlStr = result.map(item => {const dataObj = item.data.data // 取出关键数据对象return `<div class="item"><h3>${dataObj.name}</h3><ul>${dataObj.children.map(item => {return `<li><a href="javascript:;"><img src="${item.picture}"><p>${item.name}</p></a></li>`}).join('')}</ul></div>`}).join('')console.log(htmlStr)document.querySelector('.sub-list').innerHTML = htmlStr})
})

4.5.2 案例二-学习反馈

/*** 目标1:完成省市区下拉列表切换*  1.1 设置省份下拉菜单数据*  1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单*  1.3 切换城市,设置地区下拉菜单数据*/
// 1.1 设置省份下拉菜单数据
axios({url: 'http://hmajax.itheima.net/api/province'
}).then(result => {const optionStr = result.data.list.map(pname => `<option value="${pname}">${pname}</option>`).join('')document.querySelector('.province').innerHTML = `<option value="">省份</option>` + optionStr
})// 1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单
document.querySelector('.province').addEventListener('change', async e => {// 获取用户选择省份名字// console.log(e.target.value)const result = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname: e.target.value } })const optionStr = result.data.list.map(cname => `<option value="${cname}">${cname}</option>`).join('')// 把默认城市选项+下属城市数据插入select中document.querySelector('.city').innerHTML = `<option value="">城市</option>` + optionStr// 清空地区数据document.querySelector('.area').innerHTML = `<option value="">地区</option>`
})// 1.3 切换城市,设置地区下拉菜单数据
document.querySelector('.city').addEventListener('change', async e => {console.log(e.target.value)const result = await axios({url: 'http://hmajax.itheima.net/api/area', params: {pname: document.querySelector('.province').value,cname: e.target.value}})console.log(result)const optionStr = result.data.list.map(aname => `<option value="${aname}">${aname}</option>`).join('')console.log(optionStr)document.querySelector('.area').innerHTML = `<option value="">地区</option>` + optionStr
})/*** 目标2:收集数据提交保存*  2.1 监听提交的点击事件*  2.2 依靠插件收集表单数据*  2.3 基于axios提交保存,显示结果*/
// 2.1 监听提交的点击事件
document.querySelector('.submit').addEventListener('click', async () => {// 2.2 依靠插件收集表单数据const form = document.querySelector('.info-form')const data = serialize(form, { hash: true, empty: true })console.log(data)// 2.3 基于axios提交保存,显示结果try {const result = await axios({url: 'http://hmajax.itheima.net/api/feedback',method: 'POST',data})console.log(result)alert(result.data.message)} catch (error) {console.dir(error)alert(error.response.data.message)}
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/37027.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读书笔记 |【项目思维与管理】➾ 项目成为一种生存方式

读书笔记 |【项目思维与管理】➾ 项目成为一种生存方式 一、理解项目固有的挑战二、项目对企业的价值三、知识型企业的经营逻辑四、做项目管理的推进者 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 项目无处不在&#xff0c;项目已经成为…

智慧建筑工地平台,通过信息化技术、物联网、人工智能技术,实现对施工全过程的实时监控、数据分析、智能管理和优化调控

智慧工地是指通过信息化技术、物联网、人工智能技术等手段&#xff0c;对建筑工地进行数字化、智能化、网络化升级&#xff0c;实现对施工全过程的实时监控、数据分析、智能管理和优化调控。智慧工地的建设可以提高工地的安全性、效率性和质量&#xff0c;降低施工成本&#xf…

分布式唯一ID实战

目录 一、UUID二、数据库方式1、数据库生成之简单方式2、数据库生成 - 多台机器和设置步长&#xff0c;解决性能问题3、Leaf-segment 方案实现4、双 buffer 优化5、Leaf高可用容灾 三、基于Redis实现分布式ID四、雪花算法 一、UUID UUID的标准形式包含32个16进制数字&#xff…

Word 2019打开.doc文档后图片和公式不显示(呈现为白框)的解决办法

Word 2019打开.doc文档后图片和公式不显示&#xff08;呈现为白框&#xff09;的解决办法 目录 Word 2019打开.doc文档后图片和公式不显示&#xff08;呈现为白框&#xff09;的解决办法一、问题描述二、解决方法1.打开 WORD 2019&#xff0c;点击菜单中的“文件”&#xff1b;…

微服务05-Sentinel流量防卫兵

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以 流量 为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 S…

专注于创意设计,为您的小程序和网站建设带来更多的可能性

随着移动互联网的快速发展&#xff0c;越来越多的企业开始关注小程序和网站建设&#xff0c;以此来拓展业务和提升品牌形象。 在这个领域中&#xff0c;创意设计扮演着关键的角色。它不仅可以帮助企业打造独特的形象和品牌&#xff0c;还能够提高用户体验和购买决策的效率。 因…

Openlayers 实战 - 地图视野(View)- 图层 -(layer)- 资源(source)显示等级设置。

Openlayers 实战 - 地图视野&#xff08;View&#xff09;- 图层 -&#xff08;layer&#xff09;- 资源&#xff08;source&#xff09;显示等级设置。 问题原因核心代码完整代码&#xff1a;在线示例 在以往的项目维护中&#xff0c;出现一个问题&#xff0c;使用最新高清底图…

已有公司将ChatGPT集成到客服中心以增强用户体验

Ozonetel正在利用ChatGPT来改善客户体验。该公司表示&#xff0c;他们通过使用ChatGPT收集与客户互动过程收集的“语料”能够更有针对性地提高服务效率&#xff0c;提供个性化的用户体验&#xff0c;并实现更高的客户满意度。[1] 通过这套解决方案&#xff0c;客服中心将拥有一…

Struts2一次请求参数问题的记录

最近&#xff0c;一次前端正常请求&#xff0c;但后台出现请求参数值的变化&#xff0c;导致报错&#xff0c;问题如下&#xff1a; 从入参request中查看请求参数&#xff0c;是一个Json字符串&#xff0c;其中有个description的键值对&#xff1b; 但是&#xff0c;接下来调用…

【需求输出】用户故事方法

文章目录 1、初识用户故事2、用户故事是描述需求的最好方式3、创建用户故事4、用户故事的分层管理5、编写用户故事的工具 1、初识用户故事 2、用户故事是描述需求的最好方式 3、创建用户故事 4、用户故事的分层管理 5、编写用户故事的工具

软件测试基础之软件缺陷处理

一、什么是缺陷 不满足用户确定需求、影响软件功能实现的问题、故障 缺陷就是人们通常所说的bug。 ex.一下哪一种选项不属于软件缺陷___。 A.软件没有实现产品规格说明所要求的功能 B.软件中出现了产品规格说明不应该出现的功能 C.软件实现了产品规格说明没有提到的功能 D.软…

Python实现透明隧道爬虫ip:不影响现有网络结构

作为一名专业爬虫程序员&#xff0c;我们常常需要使用隧道代理来保护个人隐私和访问互联网资源。本文将分享如何使用Python实现透明隧道代理&#xff0c;以便在保护隐私的同时不影响现有网络结构。通过实际操作示例和专业的解析&#xff0c;我们将带您深入了解透明隧道代理的工…

Base64编码-算法特别的理解

Base64 在DES加密和AES加密的过程中&#xff0c;加密的编码会出现负数&#xff0c;在ascii码表中找不到对应的字符&#xff0c;就会出现乱码。为了解决乱码的问题&#xff0c;一般结合base64使用 所谓Base64&#xff0c;即是说在编码过程中使用了64种字符&#xff1a;大写A到Z、…

Azure资源命名和标记决策指南

参考 azure创建虚拟机在虚拟机中选择编辑标签&#xff0c;并添加标记&#xff0c;点击应用 3.到主页中转到所有资源 4. 添加筛选器并应用 5.查看结果&#xff0c;筛选根据给服务器定义的标签筛选出结果。 参考链接: https://learn.microsoft.com/zh-cn/azure/cloud-adoption…

在Java中操作Redis(详细-->从环境配置到代码实现)

在Java中操作Redis 文章目录 在Java中操作Redis1、介绍2、Jedis3、Spring Data Redis3.1、对String的操作3.2、对哈希类型数据的操作3.3、对list的操作3.4、对set类型的操作3.5、对 ZSet类型的数据&#xff08;有序集合&#xff09;3.6、通用类型的操作 1、介绍 Redis 的Java客…

基于Echarts的数据可视化大屏

本项目学习于b站up主&#xff08;视频链接&#xff09; up主分享的资料&#xff0c;gitee仓库&#xff1a; 其中有笔记&#xff0c;笔记链接 项目总结 项目主要分为前端页面的布局和Echarts图表的嵌入&#xff0c;页面主要就是css较为繁琐&#xff0c;图表毕竟官网有模板&…

数组slice、splice字符串substr、split

一、定义 这篇文章主要对数组操作的两种方法进行介绍和使用&#xff0c;包括&#xff1a;slice、splice。对字符串操作的两种方法进行介绍和使用&#xff0c;包括&#xff1a;substr、split (一)、数组 slice:可以操作的数据类型有&#xff1a;数组字符串 splice:数组 操作数组…

计算机网络-物理层(一)物理层的概念与传输媒体

计算机网络-物理层&#xff08;一&#xff09;物理层的概念与传输媒体 物理层相关概念 物理层的作用用来解决在各种传输媒体上传输比特0和1的问题&#xff0c;进而为数据链路层提供透明(看不见)传输比特流的服务物理层为数据链路层屏蔽了各种传输媒体的差异&#xff0c;使数据…

最新Kali Linux安装教程:从零开始打造网络安全之旅

Kali Linux&#xff0c;全称为Kali Linux Distribution&#xff0c;是一个操作系统(2013-03-13诞生)&#xff0c;是一款基于Debian的Linux发行版&#xff0c;基于包含了约600个安全工具&#xff0c;省去了繁琐的安装、编译、配置、更新步骤&#xff0c;为所有工具运行提供了一个…

[低端局][cx32L003] 移植U8G2

文章目录 一、简介&#xff08;1&#xff09;U8g2&#xff08;2&#xff09;U8x8 二、配置要求三、移植步骤&#xff08;1&#xff09;文件准备和添加&#xff08;2&#xff09;实现回调接口(I2C的读写函数)①软件I2C②硬件I2C &#xff08;3&#xff09;功能裁剪① u8g2_d_set…