流畅如丝:利用requestAnimationFrame优化你的Web动画体验
requestAnimationFrame
是前端开发中用于优化动画性能的 API。它允许浏览器在下一次重绘之前执行指定的回调函数,通常用于实现平滑的动画效果。
1.作用
-
优化性能:
requestAnimationFrame
会根据浏览器的刷新率(通常是 60Hz,即每秒 60 帧)来调用回调函数,确保动画流畅且不浪费资源。 -
节省资源:当页面不可见或最小化时,浏览器会自动暂停
requestAnimationFrame
的执行,减少 CPU 和 GPU 的消耗。 -
避免丢帧:与
setTimeout
或setInterval
相比,requestAnimationFrame
能更好地与浏览器的渲染周期同步,减少丢帧现象。
2.使用方法
-
基本用法
function animate() {// 动画逻辑requestAnimationFrame(animate); } requestAnimationFrame(animate);
-
停止动画:
let animationId; function animate() {// 动画逻辑animationId = requestAnimationFrame(animate); } animate();// 停止动画 cancelAnimationFrame(animationId);
优势对比
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>requestAnimationFrame vs setTimeout - 点击开始</title><style>.box {width: 50px;height: 50px;position: relative;top: 0;left: 0;margin-bottom: 20px; /* 增加间距 */}#rafBox {background-color: red;}#timeoutBox {background-color: blue;}.label {font-family: Arial, sans-serif;margin-bottom: 10px;}#startButton {padding: 10px 20px;font-size: 16px;margin-bottom: 20px;cursor: pointer;}</style>
</head>
<body>
<button id="startButton">开始动画</button><div><div class="label">requestAnimationFrame</div><div id="rafBox" class="box"></div>
</div>
<div><div class="label">setTimeout</div><div id="timeoutBox" class="box"></div>
</div><script>// 增加动画复杂度:模拟一些计算任务function heavyTask() {let sum = 0;for (let i = 0; i < 1000000; i++) {sum += Math.random();}}// requestAnimationFrame 动画const rafBox = document.getElementById('rafBox');let rafPosition = 0;let rafStartTime;let rafFrameCount = 0;function rafAnimate() {heavyTask(); // 模拟复杂计算rafPosition += 2; // 每次移动 2pxrafBox.style.left = rafPosition + 'px';rafFrameCount++;if (rafPosition < 600) { // 移动到 600px 时停止requestAnimationFrame(rafAnimate);} else {const rafEndTime = performance.now();console.log(`requestAnimationFrame 完成!用时:${(rafEndTime - rafStartTime).toFixed(2)}ms,帧数:${rafFrameCount}`);}}// setTimeout 动画const timeoutBox = document.getElementById('timeoutBox');let timeoutPosition = 0;let timeoutStartTime;let timeoutFrameCount = 0;function timeoutAnimate() {heavyTask(); // 模拟复杂计算timeoutPosition += 2; // 每次移动 2pxtimeoutBox.style.left = timeoutPosition + 'px';timeoutFrameCount++;if (timeoutPosition < 600) { // 移动到 600px 时停止setTimeout(timeoutAnimate, 16); // 模拟 60Hz 刷新率} else {const timeoutEndTime = performance.now();console.log(`setTimeout 完成!用时:${(timeoutEndTime - timeoutStartTime).toFixed(2)}ms,帧数:${timeoutFrameCount}`);}}// 点击按钮后启动动画const startButton = document.getElementById('startButton');startButton.addEventListener('click', () => {// 重置方块位置rafBox.style.left = '0px';timeoutBox.style.left = '0px';rafPosition = 0;timeoutPosition = 0;// 记录开始时间rafStartTime = performance.now();timeoutStartTime = performance.now();// 启动动画rafAnimate();timeoutAnimate();// 禁用按钮,防止重复点击startButton.disabled = true;});
</script>
</body>
</html>
-
你会看到一个“开始动画”按钮,点击按钮后:
-
红色方块:使用
requestAnimationFrame
,动画更加流畅。 -
蓝色方块:使用
setTimeout
,动画可能会出现卡顿。
-
打开浏览器的控制台(按 F12
),可以看到两者的完成时间和帧数对比
requestAnimationFrame
的兼容封装
requestAnimationFrame
在不同浏览器中的兼容性确实存在差异,尤其是在一些旧版本的浏览器中(如 IE9 及以下)。为了确保代码的兼容性,我们可以封装一个通用的 requestAnimationFrame
方法,如果浏览器不支持 requestAnimationFrame
,则自动降级为 setTimeout
// 兼容性封装
const requestAnimFrame = (function () {return (window.requestAnimationFrame ||window.webkitRequestAnimationFrame ||window.mozRequestAnimationFrame ||window.oRequestAnimationFrame ||window.msRequestAnimationFrame ||function (callback) {// 如果不支持 requestAnimationFrame,则使用 setTimeout 模拟return window.setTimeout(callback, 1000 / 60); // 模拟 60Hz 刷新率});
})();// 兼容性封装 cancelAnimationFrame
const cancelAnimFrame = (function () {return (window.cancelAnimationFrame ||window.webkitCancelAnimationFrame ||window.mozCancelAnimationFrame ||window.oCancelAnimationFrame ||window.msCancelAnimationFrame ||function (id) {// 如果不支持 cancelAnimationFrame,则使用 clearTimeoutwindow.clearTimeout(id);});
})();
3.使用方法
启动动画
let animationId;function animate() {// 动画逻辑animationId = requestAnimFrame(animate);
}animate(); // 启动动画
停止动画
cancelAnimFrame(animationId); // 停止动画
4.完整示例
以下是一个完整的示例,展示如何使用封装的 requestAnimFrame
方法,并且保留啦优势对比的蓝色方块,同时也增加了两个按钮,可以重复观看,以感受他们的差异!
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>requestAnimationFrame vs setTimeout 对比</title><style>.box {width: 50px;height: 50px;position: relative;top: 0;left: 0;margin-bottom: 20px; /* 增加间距 */}#rafBox {background-color: red;}#timeoutBox {background-color: blue;}.label {font-family: Arial, sans-serif;margin-bottom: 10px;}button {padding: 10px 20px;font-size: 16px;margin-right: 10px;cursor: pointer;}</style>
</head>
<body>
<button id="startButton">开始动画</button>
<button id="resetButton">重新执行动画</button><div><div class="label">requestAnimationFrame</div><div id="rafBox" class="box"></div>
</div>
<div><div class="label">setTimeout</div><div id="timeoutBox" class="box"></div>
</div><script>// 兼容性封装const requestAnimFrame = (function () {return (window.requestAnimationFrame ||window.webkitRequestAnimationFrame ||window.mozRequestAnimationFrame ||window.oRequestAnimationFrame ||window.msRequestAnimationFrame ||function (callback) {// 如果不支持 requestAnimationFrame,则使用 setTimeout 模拟return window.setTimeout(callback, 1000 / 60); // 模拟 60Hz 刷新率});})();const cancelAnimFrame = (function () {return (window.cancelAnimationFrame ||window.webkitCancelAnimationFrame ||window.mozCancelAnimationFrame ||window.oCancelAnimationFrame ||window.msCancelAnimationFrame ||function (id) {// 如果不支持 cancelAnimationFrame,则使用 clearTimeoutwindow.clearTimeout(id);});})();// requestAnimationFrame 动画const rafBox = document.getElementById('rafBox');let rafPosition = 0;let rafAnimationId;function rafAnimate() {rafPosition += 2; // 每次移动 2pxrafBox.style.left = rafPosition + 'px';if (rafPosition < 600) { // 移动到 600px 时停止rafAnimationId = requestAnimFrame(rafAnimate);}}// setTimeout 动画const timeoutBox = document.getElementById('timeoutBox');let timeoutPosition = 0;let timeoutAnimationId;function timeoutAnimate() {timeoutPosition += 2; // 每次移动 2pxtimeoutBox.style.left = timeoutPosition + 'px';if (timeoutPosition < 600) { // 移动到 600px 时停止timeoutAnimationId = setTimeout(timeoutAnimate, 16); // 模拟 60Hz 刷新率}}// 点击按钮启动动画document.getElementById('startButton').addEventListener('click', () => {// 启动 requestAnimationFrame 动画rafAnimate();// 启动 setTimeout 动画timeoutAnimate();});// 点击按钮重新执行动画document.getElementById('resetButton').addEventListener('click', () => {// 停止当前动画cancelAnimFrame(rafAnimationId);clearTimeout(timeoutAnimationId);// 重置方块位置rafBox.style.left = '0px';timeoutBox.style.left = '0px';rafPosition = 0;timeoutPosition = 0;// 重新启动动画rafAnimate();timeoutAnimate();});
</script>
</body>
</html>
5.代码说明
-
兼容性封装:
-
requestAnimFrame
和cancelAnimFrame
封装了requestAnimationFrame
和cancelAnimationFrame
的兼容性逻辑。
-
-
动画逻辑:
-
红色方块:使用
requestAnimFrame
,动画更加流畅。 -
蓝色方块:使用
setTimeout
,动画可能会出现卡顿。
-
-
按钮功能:
-
开始动画:点击后同时启动
requestAnimFrame
和setTimeout
的动画。 -
重新执行动画:点击后停止当前动画,重置方块位置,并重新启动动画。
-
6.效果展示
7.案例总结
通过这个示例,你可以直观地看到 requestAnimFrame
和 setTimeout
的差异:
-
requestAnimFrame
:动画流畅,性能更优。 -
setTimeout
:动画可能会出现卡顿。 -
备注:网上随便下载的gif录屏软件,貌似这种差异不是很明显,建议自己复制代码查看,我实际看到的还是很明显的
8.性能优化建议
-
setTimeout
的性能问题:-
丢帧:
setTimeout
的时间间隔是固定的(如 16ms 模拟 60Hz),但无法保证与浏览器的渲染周期同步,可能导致丢帧或卡顿。 -
资源浪费:即使页面不可见或最小化,
setTimeout
仍会继续运行,浪费 CPU 和 GPU 资源。 -
精度问题:
setTimeout
的时间精度受系统负载影响,可能导致动画不流畅。
-
-
requestAnimationFrame
的性能优势:-
与浏览器渲染同步:
requestAnimationFrame
会在每次浏览器重绘前调用回调函数,确保动画流畅。 -
节省资源:当页面不可见或最小化时,
requestAnimationFrame
会自动暂停,减少资源消耗。 -
高精度:
requestAnimationFrame
的时间戳精度更高,适合高性能动画。
-
9.注意事项
-
避免频繁操作 DOM:
-
在动画回调函数中,尽量减少对 DOM 的频繁操作(如修改样式或布局),因为 DOM 操作会触发重排(reflow)和重绘(repaint),影响性能。
-
可以通过以下方式优化:
-
使用
transform
和opacity
代替top
、left
等属性,因为前者不会触发重排。 -
使用
will-change
属性提示浏览器优化渲染。
-
-
-
避免阻塞主线程:
-
如果动画回调函数中有复杂的计算任务(如大量循环或递归),可能会导致主线程阻塞,影响动画流畅性。
-
可以通过以下方式优化:
-
将复杂计算任务放到 Web Worker 中执行。
-
使用
requestIdleCallback
处理低优先级的任务。
-
-
-
处理动画停止:
-
使用
cancelAnimationFrame
或clearTimeout
及时停止动画,避免不必要的资源消耗。 -
在页面不可见时(如切换标签页),可以通过
Page Visibility API
检测页面状态,暂停动画。
-
-
兼容性问题:
-
虽然
requestAnimationFrame
在现代浏览器中支持良好,但在旧版本浏览器(如 IE9 及以下)中需要降级为setTimeout
。 -
使用兼容性封装(如前面的代码)可以解决这个问题。
-
-
动画帧率控制:
-
requestAnimationFrame
的帧率通常是 60Hz,但如果动画逻辑过于复杂,可能会导致帧率下降。 -
可以通过时间戳(
performance.now()
)计算帧间隔,动态调整动画逻辑,确保帧率稳定。
-
-
内存泄漏:
-
如果动画回调函数中引用了外部变量或 DOM 元素,可能会导致内存泄漏。
-
确保在动画停止时,清理不必要的引用。
-
10.优化建议
-
使用硬件加速:
-
通过
transform: translate3d(0, 0, 0)
或will-change: transform
启用 GPU 加速,提升动画性能。
-
-
减少重排和重绘:
-
使用
transform
和opacity
实现动画,避免修改width
、height
、top
、left
等属性。
-
-
批量操作 DOM:
-
如果需要修改多个 DOM 元素的样式,可以使用
DocumentFragment
或requestAnimationFrame
批量处理,减少重排次数。
-
-
使用 Web Worker:
-
将复杂的计算任务放到 Web Worker 中执行,避免阻塞主线程。
-
-
性能监控:
-
使用
performance.now()
或浏览器开发者工具(如 Chrome 的 Performance 面板)监控动画性能,找出性能瓶颈。
-
11.优化后的动画
以下是一个优化后的动画示例,结合了上述建议:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>三个方块的性能对比</title><style>body {font-family: Arial, sans-serif;margin: 20px;}.animation-container {margin-bottom: 40px; /* 每个动画区块之间的间距 */}.label {font-size: 16px;margin-bottom: 10px; /* 文字与方块的间距 */}.box {width: 50px;height: 50px;position: relative;left: 0;}#optimizedBox {background-color: red;will-change: transform; /* 启用硬件加速 */}#unoptimizedRAFBox {background-color: green;}#unoptimizedTimeoutBox {background-color: blue;}button {padding: 10px 20px;font-size: 16px;margin-right: 10px;cursor: pointer;}</style>
</head>
<body><button id="startButton">开始动画</button><button id="resetButton">重新开始动画</button><!-- 优化后的动画 --><div class="animation-container"><div class="label">优化后的动画(requestAnimationFrame + transform)</div><div id="optimizedBox" class="box"></div></div><!-- 未优化的 requestAnimationFrame 动画 --><div class="animation-container"><div class="label">未优化的 requestAnimationFrame 动画(使用 left)</div><div id="unoptimizedRAFBox" class="box"></div></div><!-- 未优化的 setTimeout 动画 --><div class="animation-container"><div class="label">未优化的 setTimeout 动画(使用 left)</div><div id="unoptimizedTimeoutBox" class="box"></div></div><script>// 兼容性封装const requestAnimFrame = (function () {return (window.requestAnimationFrame ||window.webkitRequestAnimationFrame ||window.mozRequestAnimationFrame ||window.oRequestAnimationFrame ||window.msRequestAnimationFrame ||function (callback) {return window.setTimeout(callback, 1000 / 60);});})();const cancelAnimFrame = (function () {return (window.cancelAnimationFrame ||window.webkitCancelAnimationFrame ||window.mozCancelAnimationFrame ||window.oCancelAnimationFrame ||window.msCancelAnimationFrame ||function (id) {window.clearTimeout(id);});})();// 优化后的动画(requestAnimationFrame + transform)const optimizedBox = document.getElementById('optimizedBox');let optimizedPosition = 0;let optimizedAnimationId;function optimizedAnimate() {optimizedPosition += 2; // 每次移动 2pxoptimizedBox.style.transform = `translateX(${optimizedPosition}px)`; // 使用 transformif (optimizedPosition < 600) { // 移动到 600px 时停止optimizedAnimationId = requestAnimFrame(optimizedAnimate);}}// 未优化的 requestAnimationFrame 动画(使用 left)const unoptimizedRAFBox = document.getElementById('unoptimizedRAFBox');let unoptimizedRAFPosition = 0;let unoptimizedRAFAnimationId;function unoptimizedRAFAnimate() {unoptimizedRAFPosition += 2; // 每次移动 2pxunoptimizedRAFBox.style.left = unoptimizedRAFPosition + 'px'; // 使用 leftif (unoptimizedRAFPosition < 600) { // 移动到 600px 时停止unoptimizedRAFAnimationId = requestAnimFrame(unoptimizedRAFAnimate);}}// 未优化的 setTimeout 动画(使用 left)const unoptimizedTimeoutBox = document.getElementById('unoptimizedTimeoutBox');let unoptimizedTimeoutPosition = 0;let unoptimizedTimeoutAnimationId;function unoptimizedTimeoutAnimate() {unoptimizedTimeoutPosition += 2; // 每次移动 2pxunoptimizedTimeoutBox.style.left = unoptimizedTimeoutPosition + 'px'; // 使用 leftif (unoptimizedTimeoutPosition < 600) { // 移动到 600px 时停止unoptimizedTimeoutAnimationId = setTimeout(unoptimizedTimeoutAnimate, 16); // 模拟 60Hz 刷新率}}// 点击按钮启动动画document.getElementById('startButton').addEventListener('click', () => {// 启动优化后的动画optimizedAnimate();// 启动未优化的 requestAnimationFrame 动画unoptimizedRAFAnimate();// 启动未优化的 setTimeout 动画unoptimizedTimeoutAnimate();});// 点击按钮重新开始动画document.getElementById('resetButton').addEventListener('click', () => {// 停止当前动画cancelAnimFrame(optimizedAnimationId);cancelAnimFrame(unoptimizedRAFAnimationId);clearTimeout(unoptimizedTimeoutAnimationId);// 重置方块位置optimizedBox.style.transform = 'translateX(0px)';unoptimizedRAFBox.style.left = '0px';unoptimizedTimeoutBox.style.left = '0px';optimizedPosition = 0;unoptimizedRAFPosition = 0;unoptimizedTimeoutPosition = 0;// 重新启动动画optimizedAnimate();unoptimizedRAFAnimate();unoptimizedTimeoutAnimate();});</script>
</body>
</html>
12.效果展示
csdn上gif大小不能超过5M,我这动图超过5M啦,在线压缩居然要收费,算了!
大家自己复制源码感受一下吧!不贴gif图啦,jpg的对付着看吧!!!
你可以清晰地看到三种实现方式的性能差异:
-
优化后的动画:使用
requestAnimationFrame
和transform
,性能最佳。 -
未优化的
requestAnimationFrame
动画:使用left
,性能稍差。 -
未优化的
setTimeout
动画:使用left
,性能最差。
13.总结
通过优化 DOM 操作、启用硬件加速、减少重排和重绘,可以显著提升动画性能。同时,注意兼容性和资源管理,确保动画在不同设备和浏览器中都能流畅运行。
相关文章:
流畅如丝:利用requestAnimationFrame优化你的Web动画体验
requestAnimationFrame 是前端开发中用于优化动画性能的 API。它允许浏览器在下一次重绘之前执行指定的回调函数,通常用于实现平滑的动画效果。 1.作用 优化性能:requestAnimationFrame 会根据浏览器的刷新率(通常是 60Hz,即每秒…...
OpenCV 基础模块 Python 版
OpenCV 基础模块权威指南(Python 版) 一、模块全景图 plaintext OpenCV 架构 (v4.x) ├─ 核心层 │ ├─ core:基础数据结构与操作(Mat/Scalar/Point) │ └─ imgproc:图像处理流水线(滤…...
代码随想录算法训练营第十五天 | 数组 |长度最小的子数组和螺旋矩阵II
长度最小的子数组 【题目简介】 【自写数组解法】 class Solution:def minSubArrayLen(self, target: int, nums: List[int]) -> int:minLength float(inf)slow 0fast 0cur_sum nums[slow]# 终止条件:fast不能超过最大索引值while slow < fast and fas…...
C++ 入门第27天:异常处理详细讲解
往期回顾: C 入门第24天:C11 多线程基础-CSDN博客 C 入门第25天:线程池(Thread Pool)基础-CSDN博客 C 入门第26天:文件与流操作基础-CSDN博客 C 入门第27天:异常处理详细讲解 前言 在 C 开发中…...
Powershell WSL导出导入ubuntu22.04.5子系统
导出Linux子系统 导出位置在C盘下,根据自己的实际情况更改即可Write-Host "export ubuntu22.04.5" -ForegroundColor Green wsl --export Ubuntu-22.04 c:\Ubuntu-22.04.tar 导入Linux子系统 好处是目录可用在任意磁盘路径,便于迁移不同的设备之间Write-Host &quo…...
中文文献去哪里查找,个人下载知网、万方、维普文献途径
国内三大知识库知网、万方、维普是查找中文文献常用数据库,本文将以实例演示个人下载这三个数据库文献的途径及过程。 先说下途径: 获取知网、万方、维普数据库资源可去文献党下载器网站: 使用方法: 在文献党下载器官网下载安装…...
玩转C#函数:参数、返回值与游戏中的攻击逻辑封装
Langchain系列文章目录 01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...
简易shell
自主实现shell done,故意写成,表示先赋值,再判断,分割之后,strtok会返回NULL,刚好让gArgv最后一个元素是NULL,并且while判断结束 Makefile 1 myshell:myshell.c …...
注意力机制,本质上是在做什么?
本文以自注意机制为例,输入一个4*4的矩阵 如下: input_datatorch.tensor([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16] ],dtypetorch.float) 得到Q和K的转置如下。 此时,计算QK^T ,得到如下结果 第一行第一个位置就是第一条样本和第…...
【机器学习-模型评估】
“评估”已建立的模型 在进行回归和分类时,为了进行预测,定义了预测函数fθ(x) 然后根据训练数据求出了预测函数的参数θ(即对目标函数进行微分,然后求出参数更新表达式的操作) 之前求出参数更新表达式之后就结束了。但是,其实我…...
19681 01背包
19681 01背包 ⭐️难度:中等 🌟考点:动态规划、01背包 📖 📚 import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; import java.util.Scanner;public class Main {static int N 10001…...
Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测
Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测 目录 Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预…...
基于CAMEL 的Workforce 实现多智能体协同工作系统
文章目录 一、workforce 简介1.架构设计2.通信机制 二、workforce 工作流程图示例1.用户角色2.工作流程 三、workforce 中重要函数说明1.__init__函数2.add_single_agent_worker 函数3.add_role_playing_worker 函数4.add_workforce 函数 四、基于workforce实现多智能体协调&am…...
炫酷的3D按钮效果实现 - CSS3高级特性应用
炫酷的3D按钮效果实现 - CSS3高级特性应用 这里写目录标题 炫酷的3D按钮效果实现 - CSS3高级特性应用项目介绍核心技术实现1. 基础结构设计2. 视觉效果实现2.1 背景渐变2.2 立体感营造 3. 交互动效设计3.1 悬停效果3.2 按压效果 技术要点分析1. 深度层次感2. 动画过渡3. 性能优…...
AI视频是否会影响原创价值
AI视频是否会影响原创价值 AI视频带来全民创意对原创内容的影响 随着AI技术的发展,AI视频技术在视频领域的影响也逐渐凸显,从自动剪辑、特效生成到基于文本或语音自动生成视频内容,这一系列的进步极大地降低了视频制作的技术门槛与成本。这种…...
代码随想录刷题day50|(回溯算法篇)131.分割回文串▲
目录 一、回溯算法基础知识 二、分割回文串思路 2.1 如何切割 2.2 判断回文 2.3 回溯三部曲 2.4 其他问题 三、相关算法题目 四、总结 一、回溯算法基础知识 详见:代码随想录刷题day46|(回溯算法篇)77.组合-CSDN博客 二、分割回文…...
SpringCloud 学习笔记3(OpenFeign)
OpenFeign 微服务之间的通信方式,通常有两种:RPC 和 HTTP。 简言之,RPC 就是像调用本地方法一样调用远程方法。 在 SpringCloud 中,默认是使用 HTTP 来进行微服务的通信,最常用的实现形式有两种: RestTem…...
Python与区块链隐私保护技术:如何在去中心化世界中保障数据安全
Python与区块链隐私保护技术:如何在去中心化世界中保障数据安全 在区块链世界里,透明性和不可篡改性是两大核心优势,但这也带来了一个悖论——如何在公开账本的同时保障用户隐私?如果你的交易记录对所有人可见,如何防止敏感信息泄露? Python 作为区块链开发中最受欢迎的…...
基于32单片机的无人机直流电机闭环调速系统设计
标题:基于32单片机的无人机直流电机闭环调速系统设计 内容:1.摘要 本文针对无人机直流电机调速需求,设计了基于32单片机的无人机直流电机闭环调速系统。背景在于无人机应用场景不断拓展,对电机调速精度和稳定性要求日益提高。目的是开发一套高精度、响应…...
QT 图表(拆线图,栏状图,饼状图 ,动态图表)
效果 折线图 // 创建折线数据系列// 创建折线系列QLineSeries *series new QLineSeries;// series->append(0, 6);// series->append(2, 4);// series->append(3, 8);// 创建图表并添加系列QChart *chart new QChart;chart->addSeries(series);chart->setTit…...
预测性维护:Ubuntu边缘计算机如何降低电梯故障率
在现代城市中,电梯作为垂直交通的重要工具,其运行状态直接关系到人们的出行安全和效率。传统的电梯监控系统往往依赖于中心化的数据处理,存在响应慢、数据量大、实时性差等问题。而边缘协议网关(Edge Protocol Gateway)…...
MyBatis plus详解
核心功能 代码生成器 它能够依据数据库表结构,自动生成涵盖实体类、Mapper 接口、Mapper XML 文件、Service 接口与实现类等在内的基础代码。开发人员只需简单配置数据库连接信息、表名以及生成代码的相关参数,即可快速生成符合项目规范的基础代码&…...
【数据挖掘】数据预处理——以鸢尾花数据集为例
数据预处理——以鸢尾花数据集为例 一、实验手册(一)实验目的(二)实验原理(三)实验环境(四)实验步骤(五)实验报告要求 二、案例代码(以鸢尾花数据…...
根据文件名称查询文件所在位置
在 Linux 中,根据文件名称查询文件所在位置主要通过命令行工具实现,以下是几种常用方法: --- ### **1. 使用 find 命令(最灵活)** find 命令可以递归搜索指定目录下的文件,支持按名称、类型、时间等条件过…...
记一次wsl2+docker无法运行的经历
前情提要 由于某个大创项目的需要和对猫娘机器人的迫切渴求(bushi 需要在电脑里面安装docker desktop。由于电脑里面安装了wsl2环境 因此决定使用wsl2dockerdesktop的方式配置docker 遇到的问题 在像往常一样安装docker desktop并且启动时 提示错误: …...
XSS介绍通关XSS-Labs靶场
目录 XSS XSS的类型 1.存储型XSS(PXSS): 2. 反射型XSS(N-PXSS): 3. DOM型XSS: 4. 突变型XSS(mXSS): 5. 通用型XSS(UXSS)&#x…...
枚举的定义及其使用
在Java中,enum(枚举)是一个特殊的类,用于表示一组常量。enum类型在Java中提供了一种类型安全的方式来定义常量,相比传统的常量(如public static final变量),它更加简洁、类型安全&am…...
[特殊字符][特殊字符][特殊字符][特殊字符][特殊字符][特殊字符]壁紙 流光染墨,碎影入梦
#Cosplay #🧚♀️Bangni邦尼🐰. #📷 穹妹 Set.01 #后期圈小程序 琼枝低垂,霜花浸透夜色,风起时,微光轻拂檐角,洒落一地星辉。远山隐于烟岚,唯余一抹青黛,勾勒出天光水…...
996引擎-接口测试:消息Tips
996引擎-接口测试:消息Tips 发送视野内广播消息 sendrefluamsg发送聊天框消息 sendmsg发送地图消息 sendmapmsg打印消息到控制台 release_print发送自定义颜色的文字信息 guildnoticemsg测试NPC参考资料发送视野内广播消息 sendrefluamsg function npc_test_onclick1(player)-…...
Redis设计与实现-底层实现
Redis底层实现 1、事件1.1 文件事件1.2 时间事件1.3 事件调度 2、Redis客户端2.1 客户端的相关属性2.2 客户端的创建与关闭2.2.1 普通客户端的创建2.2.2 普通客户端的关闭2.2.3 AOF的伪客户端2.2.4 Lua脚本的伪客户端 3、Redis服务端3.1 命令请求的执行过程3.1.1 客户端发送命令…...
acwing1295. X的因子链
题目链接:1295. X的因子链 - AcWing题库 算法:数论线性筛法求素数 x如果想要尽可能多的分为几个因子,那么就应该分成素数,因为如果是合数说明还能分。 题目要求求出①这段序列的最大长度和②最大长度序列的个数 最大长度&#x…...
练习-班级活动(map存储键值对)
问题描述 小明的老师准备组织一次班级活动。班上一共有 n 名 (n 为偶数) 同学,老师想把所有的同学进行分组,每两名同学一组。为了公平,老师给每名同学随机分配了一个 n 以内的正整数作为 id,第 i 名同学的 id 为 ai。 老师希望…...
34-三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。 方法一&…...
Excel online开始支持Copilot高级数据分析:Python提供强大的数据见解
前文讲过Excel中的copilot可以直接调用Python进行高级数据分析: Copilot:Excel中的Python高级分析来了 Python in Excel高级分析:一键RFM分析 超越DeepSeek:Copilot in Excel高级数据分析原生支持Python无需安装软件 零代码、…...
【数据结构】kmp算法介绍+模板代码
目录 1.kmp算法介绍 2.应用场景 3.KMP与暴力算法比较 4.模板代码 KMP算法是一种高效的字符串匹配算法,用于在文本串中快速查找模式串的所有出现位置。其核心思想是通过预处理模式串,避免在匹配失败时进行不必要的回溯,从而将时间复杂度优…...
python关键字汇总
文章目录 1. 变量与类型相关2. 控制流相关3. 函数与类相关4. 异常处理相关5. 模块相关6. 其他 在 Python 3 里有 35 个关键字,它们各自具备特定的用途与意义 1. 变量与类型相关 True、False 意义:布尔类型的常量,分别代表逻辑真与逻辑假。示…...
六十天前端强化训练之第二十五天之组件生命周期大师级详解(Vue3 Composition API 版)
欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗,谢谢大佬! 目录 一、生命周期核心知识 1.1 生命周期全景图 1.2 生命周期钩子详解 1.2.1 初始化阶段 1.2.2 挂载阶段 1.2.3 更新阶段 1.2.4 卸载阶段 1.3 生命周期执行顺序 1.4 父子组…...
油候插件、idea、VsCode插件推荐(自用)
开发软件: 之前的文章: 开发必装最实用工具软件与网站 推荐一下我使用的开发工具 目前在用的 油候插件 AC-baidu-重定向优化百度搜狗谷歌必应搜索_favicon_双列 让查询变成多列,而且可以流式翻页 Github 增强 - 高速下载 github下载 TimerHo…...
R语言基于ggscitable包复现一篇3.5分的文章的连续变量交互效应(交互作用)的可视化图
交互作用效应(p for Interaction)在SCI文章中可以算是一个必杀技,几乎在高分的SCI中必出现,因为把人群分为亚组后再进行统计可以增强文章结果的可靠性,进行可视化后可以清晰的表明变量之间的关系。不仅如此,交互作用还可以使用来进…...
mac环境下chatwoot客服聊天docker本地部署+对接通义千问Qwen2.5
🚀 安装docker-desktop 🚀 定义一个.env环境变量文件docker-compose.yaml .env # Learn about the various environment variables at # https://www.chatwoot.com/docs/self-hosted/configuration/environment-variables/#rails-production-variables…...
mac上安装nvm及nvm的基本语法使用!!
种一棵树,最好是十年前,其次是现在!想要改变,从此刻开始,一切都不晚! 目录 nvm是什么?前提条件:安装homebrew如果系统已经有node版本:在mac上安装nvm:用nvm安…...
论文阅读:2024-NAACL Semstamp、2024-ACL (Findings) k-SemStamp
总目录 大模型安全相关研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 Semstamp: A semantic watermark with paraphrastic robustness for text generation https://aclanthology.org/2024.naacl-long.226/ k-SemStamp: A Clustering-Based Semantic Wate…...
本地JAR批量传私服
在有网络隔离的环境下,Maven项目如果没有搭建私服就得把用到的通用组件通过U盘在每个组员间拷贝来拷贝去。非常的麻烦跟低效。搭建私服,如果通用组件很多的时候手工一个一个上传更是非常的麻烦跟低效; 我就遇上这问题,跟A公司合作…...
Linux上位机开发实战(camera视频读取)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 关于linux camera,一般都是认为是mipi camera,或者是usb camera。当然不管是哪一种,底层的逻辑都是v4l2&#x…...
OpenCV图像处理基础1
OpenCV 提供了丰富的图像处理和计算机视觉功能,包括图像读取、显示、颜色空间转换、滤波、边缘检测、轮廓检测等。 本章将介绍 OpenCV 的基本概念和常用功能。 图像的表示和处理 OpenCV 通过 NumPy 数组 来表示图像数据,每个图像就是一个多维数组,其中每个元素对应图像中的…...
Python Web 框架 Django、Flask 和 FastAPI 对比
在探索 Python Web 框架时,Django、Flask 和 FastAPI 无疑是最常被提及的名字。根据我们最新的 Python 开发者调查,这三大框架继续稳坐后端 Web 开发的热门宝座。它们均为开源项目,并且与 Python 的最新版本无缝兼容。然而,面对不…...
TISAX认证注意事项的详细介绍
TISAX(Trusted Information Security Assessment Exchange)认证的注意事项犹如企业在信息安全领域航行时必须遵循的灯塔指引,至关重要且不容忽视。以下是对TISAX认证注意事项的详尽阐述: 首先,企业需深入研读并理解TI…...
JavaScript |(六)DOM事件 | 尚硅谷JavaScript基础实战
学习来源:尚硅谷JavaScript基础&实战丨JS入门到精通全套完整版 笔记来源:在这位大佬的基础上添加了一些东西,欢迎大家支持原创,大佬太棒了:JavaScript |(六)DOM事件 | 尚硅谷JavaScript基础…...
【动态规划】详解混合背包问题
目录 1. 前置文章2. 题目3. 小结 1. 前置文章 本文前置文章: 【动态规划】详解 0-1背包问题【动态规划】详解完全背包问题【动态规划】详解分组背包问题【动态规划】详解多重背包问题 下面是三种背包模式的区别: 0 - 1 背包 是说:有 n 个…...
Nodejs 项目打包部署方式
方式一:PM2 一、准备工作 确保服务器上已安装 Node.js 环境建议使用 PM2 进行进程管理(需要额外安装) 二、部署步骤 1.首先在服务器上安装 PM2(推荐): npm install -g pm22.将项目代码上传到服务器&…...