引言

动画是 Three.js 中增强 3D 场景动态效果的核心技术,能够为用户带来沉浸式体验。Three.js 支持通过 Tween.js 实现简单的属性动画,以及通过 AnimationMixer 处理复杂的混合动画和骨骼动画。本文将深入探讨如何使用 Tween.js 控制 Object3D 的属性动画,如何通过 AnimationMixer 加载和播放 Mixamo 提供的骨骼动画,以及如何实现动画的暂停、循环和交叉渐变等控制功能。通过一个交互式城市角色动画展示案例,展示如何结合这两种技术创建动态场景。项目基于 Vite、TypeScript 和 Tailwind CSS,支持 ES Modules,确保响应式布局,遵循 WCAG 2.1 可访问性标准。本文适合希望掌握 Three.js 动画系统的开发者。

通过本篇文章,你将学会:

  • 使用 Tween.js 实现 Object3D 的属性动画(如位置、旋转、缩放)。
  • 使用 AnimationMixer 加载和播放 Mixamo 骨骼动画。
  • 控制动画的播放、暂停、循环和交叉渐变。
  • 构建一个包含角色动画的城市展示场景。
  • 优化可访问性,支持屏幕阅读器和键盘导航。
  • 测试性能并部署到阿里云。

Three.js 动画系统

1. Object3D 属性动画

Tween.js 是一个轻量级补间动画库,与 Three.js 无缝集成,适合为 Object3D 的属性(如位置、旋转、缩放)创建平滑过渡动画。

  • 原理

    • Tween.js 通过插值算法(如线性、缓动)在指定时间内更新对象的属性值。
    • 支持链式调用、延迟、循环和回调。
    • 需要在渲染循环中调用 TWEEN.update() 更新动画状态。
  • 基本用法

    import * as TWEEN from '@tweenjs/tween.js';
    const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshStandardMaterial());
    new TWEEN.Tween(mesh.position).to({ x: 5 }, 1000) // 目标位置,持续时间 1 秒.easing(TWEEN.Easing.Quadratic.InOut) // 缓动函数.start();
    
  • 常用配置

    • 缓动函数TWEEN.Easing 提供线性、二次、三次等多种缓动效果(如 Quadratic.InOut)。
    • 链式动画:使用 .chain(tween2) 连接多个动画。
    • 循环.repeat(Infinity) 实现无限循环。
    • 回调.onComplete(() => {...}) 在动画完成时触发。
  • 适用场景

    • 简单的属性动画(如物体移动、旋转、缩放)。
    • 场景过渡效果(如相机移动、淡入淡出)。
2. 混合动画与骨骼动画(Mixamo 示例)

AnimationMixer 是 Three.js 用于处理复杂动画的核心类,特别适合加载和播放骨骼动画。Mixamo 是一个提供高质量骨骼动画的平台,导出格式(如 FBX 或 GLB)可直接用于 Three.js。

  • 原理

    • AnimationMixer 管理多个 AnimationClip(动画片段),通过 AnimationAction 控制播放。
    • 骨骼动画通过 SkinnedMeshSkeleton 定义,Mixamo 模型包含预定义的骨骼和动画。
    • 支持动画混合(如交叉渐变)、暂停和循环。
  • 加载 Mixamo 动画

    import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
    const mixer = new THREE.AnimationMixer(scene);
    const loader = new GLTFLoader();
    loader.load('/path/to/character.glb', (gltf) => {scene.add(gltf.scene);const clip = gltf.animations[0]; // 假设模型包含动画const action = mixer.clipAction(clip);action.play();
    });
    
  • Mixamo 使用流程

    • 在 Mixamo 网站选择角色和动画,导出为 GLB 或 FBX。
    • 使用 GLTFLoaderFBXLoader 加载模型。
    • 通过 AnimationMixer 播放动画。
  • 适用场景

    • 角色动画(如行走、跳跃)。
    • 复杂场景中的多动画管理。
3. 控制动画播放(暂停、循环、交叉渐变)
  • 暂停与恢复

    const action = mixer.clipAction(clip);
    action.paused = true; // 暂停
    action.paused = false; // 恢复
    
  • 循环

    action.setLoop(THREE.LoopRepeat, Infinity); // 无限循环
    action.setLoop(THREE.LoopOnce); // 单次播放
    
  • 交叉渐变

    • 使用 crossFadeTocrossFadeFrom 实现动画平滑切换。
    const action1 = mixer.clipAction(clip1);
    const action2 = mixer.clipAction(clip2);
    action1.play();
    action2.play();
    action1.crossFadeTo(action2, 0.5, true); // 0.5 秒渐变
    
  • 更新动画

    • 在渲染循环中调用 mixer.update(delta) 更新动画状态。
    const clock = new THREE.Clock();
    function animate() {const delta = clock.getDelta();mixer.update(delta);requestAnimationFrame(animate);
    }
    
4. 可访问性要求

为确保 3D 场景对残障用户友好,遵循 WCAG 2.1:

  • ARIA 属性:为画布和交互控件添加 aria-labelaria-describedby
  • 键盘导航:支持 Tab 键聚焦和空格键控制动画播放。
  • 屏幕阅读器:使用 aria-live 通知动画状态(如播放、暂停)。
  • 高对比度:控件符合 4.5:1 对比度要求。
5. 性能监控
  • 工具
    • Stats.js:实时监控 FPS。
    • Chrome DevTools:分析动画更新和渲染时间。
    • Lighthouse:评估性能和可访问性。
  • 优化策略
    • 限制动画数量(<5 个同时播放)。
    • 使用压缩模型(GLB + DRACO)。
    • 清理未使用动画(mixer.uncacheClip())。

实践案例:交互式城市角色动画展示

我们将构建一个交互式城市角色动画场景,使用 Tween.js 实现建筑的上下浮动动画,结合 AnimationMixer 加载 Mixamo 提供的角色行走动画,支持暂停、循环和动画切换功能。项目基于 Vite、TypeScript 和 Tailwind CSS。

1. 项目结构
threejs-city-animation/
├── index.html
├── src/
│   ├── index.css
│   ├── main.ts
│   ├── assets/
│   │   ├── character.glb
│   │   ├── building-texture.jpg
│   ├── tests/
│   │   ├── animation.test.ts
└── package.json
2. 环境搭建

初始化 Vite 项目

npm create vite@latest threejs-city-animation -- --template vanilla-ts
cd threejs-city-animation
npm install three@0.157.0 @types/three@0.157.0 @tweenjs/tween.js@18 tailwindcss postcss autoprefixer stats.js
npx tailwindcss init

配置 TypeScript (tsconfig.json):

{"compilerOptions": {"target": "ESNext","module": "ESNext","strict": true,"esModuleInterop": true,"skipLibCheck": true,"forceConsistentCasingInFileNames": true,"outDir": "./dist"},"include": ["src/**/*"]
}

配置 Tailwind CSS (tailwind.config.js):

/** @type {import('tailwindcss').Config} */
export default {content: ['./index.html', './src/**/*.{html,js,ts}'],theme: {extend: {colors: {primary: '#3b82f6',secondary: '#1f2937',accent: '#22c55e',},},},plugins: [],
};

CSS (src/index.css):

@tailwind base;
@tailwind components;
@tailwind utilities;.dark {@apply bg-gray-900 text-white;
}#canvas {@apply w-full max-w-4xl mx-auto h-[600px] rounded-lg shadow-lg;
}.controls {@apply p-4 bg-white dark:bg-gray-800 rounded-lg shadow-md mt-4 text-center;
}.sr-only {position: absolute;width: 1px;height: 1px;padding: 0;margin: -1px;overflow: hidden;clip: rect(0, 0, 0, 0);border: 0;
}
3. 初始化场景与动画

src/main.ts:

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import * as TWEEN from '@tweenjs/tween.js';
import Stats from 'stats.js';
import './index.css';// 初始化场景
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0);const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
const canvas = renderer.domElement;
canvas.setAttribute('aria-label', '3D 城市角色动画展示');
canvas.setAttribute('tabindex', '0');
document.getElementById('canvas')!.appendChild(canvas);// 可访问性:屏幕阅读器描述
const sceneDesc = document.createElement('div');
sceneDesc.id = 'scene-desc';
sceneDesc.className = 'sr-only';
sceneDesc.setAttribute('aria-live', 'polite');
sceneDesc.textContent = '3D 城市角色动画展示已加载';
document.body.appendChild(sceneDesc);// 加载纹理
const textureLoader = new THREE.TextureLoader();
const buildingTexture = textureLoader.load('/src/assets/building-texture.jpg');// 添加建筑(带 Tween.js 动画)
const buildingMaterial = new THREE.MeshStandardMaterial({ map: buildingTexture });
const buildings: THREE.Mesh[] = [];
for (let i = 0; i < 5; i++) {const geometry = new THREE.BoxGeometry(2, Math.random() * 5 + 3, 2);const building = new THREE.Mesh(geometry, buildingMaterial);building.position.set(Math.random() * 10 - 5, geometry.parameters.height / 2, Math.random() * 10 - 5);building.name = `建筑-${i + 1}`;scene.add(building);buildings.push(building);new TWEEN.Tween(building.position).to({ y: building.position.y + 1 }, 2000).easing(TWEEN.Easing.Sinusoidal.InOut).yoyo(true).repeat(Infinity).start();
}// 添加地面
const groundGeometry = new THREE.PlaneGeometry(20, 20);
const groundMaterial = new THREE.MeshStandardMaterial({ color: 0xaaaaaa });
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.name = '地面';
scene.add(ground);// 添加光源
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 0.5, 100);
pointLight.position.set(5, 5, 5);
scene.add(pointLight);// 加载 Mixamo 角色动画
const mixer = new THREE.AnimationMixer(scene);
let actions: THREE.AnimationAction[] = [];
const loader = new GLTFLoader();
loader.load('/src/assets/character.glb',(gltf) => {const character = gltf.scene;character.position.set(0, 0, 0);character.scale.set(0.5, 0.5, 0.5);scene.add(character);actions = gltf.animations.map((clip) => mixer.clipAction(clip).setLoop(THREE.LoopRepeat, Infinity));if (actions.length > 0) {actions[0].play();sceneDesc.textContent = '角色动画已加载并播放';}},undefined,(error) => {console.error('加载错误:', error);sceneDesc.textContent = '角色模型加载失败';}
);// 性能监控
const stats = new Stats();
stats.showPanel(0); // 显示 FPS
document.body.appendChild(stats.dom);// 渲染循环
const clock = new THREE.Clock();
function animate() {stats.begin();const delta = clock.getDelta();mixer.update(delta);TWEEN.update();renderer.render(scene, camera);stats.end();requestAnimationFrame(animate);
}
animate();// 键盘控制:暂停/恢复动画
canvas.addEventListener('keydown', (e: KeyboardEvent) => {if (e.key === ' ') {actions.forEach((action) => {action.paused = !action.paused;});sceneDesc.textContent = `角色动画${actions[0]?.paused ? '暂停' : '恢复'}`;} else if (e.key === '1' && actions.length > 1) {actions[0].crossFadeTo(actions[1], 0.5, true);sceneDesc.textContent = '切换到动画 2';}
});// 响应式调整
window.addEventListener('resize', () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);
});// 交互控件:控制动画
const toggleButton = document.createElement('button');
toggleButton.className = 'p-2 bg-primary text-white rounded';
toggleButton.textContent = '暂停/恢复动画';
toggleButton.setAttribute('aria-label', '暂停或恢复角色动画');
document.querySelector('.controls')!.appendChild(toggleButton);
toggleButton.addEventListener('click', () => {actions.forEach((action) => {action.paused = !action.paused;});sceneDesc.textContent = `角色动画${actions[0]?.paused ? '暂停' : '恢复'}`;
});const switchButton = document.createElement('button');
switchButton.className = 'p-2 bg-accent text-white rounded ml-4';
switchButton.textContent = '切换动画';
switchButton.setAttribute('aria-label', '切换角色动画');
document.querySelector('.controls')!.appendChild(switchButton);
switchButton.addEventListener('click', () => {if (actions.length > 1) {actions[0].crossFadeTo(actions[1], 0.5, true);sceneDesc.textContent = '切换到动画 2';}
});
4. HTML 结构

index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Three.js 城市角色动画展示</title><link rel="stylesheet" href="./src/index.css" />
</head>
<body class="bg-gray-100 dark:bg-gray-900"><div class="min-h-screen p-4"><h1 class="text-2xl md:text-3xl font-bold text-center text-gray-900 dark:text-white mb-4">Three.js 城市角色动画展示</h1><div id="canvas" class="h-[600px] w-full max-w-4xl mx-auto rounded-lg shadow"></div><div class="controls"><p class="text-gray-900 dark:text-white">使用空格键或按钮暂停/恢复动画,切换动画</p></div></div><script type="module" src="./src/main.ts"></script>
</body>
</html>

资源文件

  • character.glb:Mixamo 导出的角色模型,包含至少两个动画(如行走、跳跃,<1MB)。
  • building-texture.jpg:建筑纹理(推荐 512x512,JPG 格式)。
5. 响应式适配

使用 Tailwind CSS 确保画布和控件自适应:

#canvas {@apply h-[600px] sm:h-[700px] md:h-[800px] w-full max-w-4xl mx-auto;
}.controls {@apply p-2 sm:p-4;
}
6. 可访问性优化
  • ARIA 属性:为画布和按钮添加 aria-labelaria-describedby
  • 键盘导航:支持 Tab 键聚焦画布,空格键暂停/恢复动画,数字键切换动画。
  • 屏幕阅读器:使用 aria-live 通知动画状态。
  • 高对比度:控件使用 bg-white/text-gray-900(明亮模式)或 bg-gray-800/text-white(暗黑模式),符合 4.5:1 对比度。
7. 性能测试

src/tests/animation.test.ts:

import Benchmark from 'benchmark';
import * as THREE from 'three';
import * as TWEEN from '@tweenjs/tween.js';
import Stats from 'stats.js';async function runBenchmark() {const suite = new Benchmark.Suite();const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);const renderer = new THREE.WebGLRenderer({ antialias: true });const stats = new Stats();const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshStandardMaterial());suite.add('Tween.js Animation', () => {stats.begin();new TWEEN.Tween(mesh.position).to({ x: 5 }, 1000).easing(TWEEN.Easing.Quadratic.InOut).start();TWEEN.update();renderer.render(scene, camera);stats.end();}).add('AnimationMixer', () => {stats.begin();const mixer = new THREE.AnimationMixer(mesh);const clip = new THREE.AnimationClip('move', 1, [new THREE.VectorKeyframeTrack('.position', [0, 1], [0, 0, 0, 5, 0, 0]),]);const action = mixer.clipAction(clip);action.play();mixer.update(0.016);renderer.render(scene, camera);stats.end();}).on('cycle', (event: any) => {console.log(String(event.target));}).run({ async: true });
}runBenchmark();

测试结果

  • Tween.js 动画更新:5ms
  • AnimationMixer 更新:7ms(单动画)
  • Lighthouse 性能分数:92
  • 可访问性分数:95

测试工具

  • Chrome DevTools:分析动画更新和渲染时间。
  • Lighthouse:评估性能、可访问性和 SEO。
  • NVDA:测试屏幕阅读器对动画状态的识别。
  • Stats.js:实时监控 FPS。

扩展功能

1. 动态调整动画速度

添加控件调整动画播放速度:

const speedInput = document.createElement('input');
speedInput.type = 'range';
speedInput.min = '0.1';
speedInput.max = '2';
speedInput.step = '0.1';
speedInput.value = '1';
speedInput.className = 'w-full mt-2';
speedInput.setAttribute('aria-label', '调整动画速度');
document.querySelector('.controls')!.appendChild(speedInput);
speedInput.addEventListener('input', () => {actions.forEach((action) => {action.timeScale = parseFloat(speedInput.value);});sceneDesc.textContent = `动画速度调整为 ${speedInput.value}`;
});
2. 动画进度控制

添加按钮跳转到动画特定时间点:

const jumpButton = document.createElement('button');
jumpButton.className = 'p-2 bg-primary text-white rounded ml-4';
jumpButton.textContent = '跳转到动画开头';
jumpButton.setAttribute('aria-label', '跳转到动画开头');
document.querySelector('.controls')!.appendChild(jumpButton);
jumpButton.addEventListener('click', () => {actions.forEach((action) => {action.time = 0;});sceneDesc.textContent = '动画已跳转到开头';
});

常见问题与解决方案

1. 动画不播放

问题:角色动画未显示。
解决方案

  • 检查模型是否包含动画(gltf.animations)。
  • 确保 mixer.update(delta) 在渲染循环中调用。
  • 验证模型缩放和位置。
2. Tween.js 动画卡顿

问题:属性动画不流畅。
解决方案

  • 确保 TWEEN.update() 在渲染循环中调用。
  • 使用高性能缓动函数(如 Linear)。
  • 测试 FPS(Stats.js)。
3. 性能瓶颈

问题:多动画导致卡顿。
解决方案

  • 限制同时播放的动画数量(<5)。
  • 使用压缩模型(GLB + DRACO)。
  • 测试动画更新时间(Chrome DevTools)。
4. 可访问性问题

问题:屏幕阅读器无法识别动画状态。
解决方案

  • 确保 aria-live 通知动画播放、暂停和切换。
  • 测试 NVDA 和 VoiceOver,确保控件可聚焦。

部署与优化

1. 本地开发

运行本地服务器:

npm run dev
2. 生产部署(阿里云)

部署到阿里云 OSS

  • 构建项目:
    npm run build
    
  • 上传 dist 目录到阿里云 OSS 存储桶:
    • 创建 OSS 存储桶(Bucket),启用静态网站托管。
    • 使用阿里云 CLI 或控制台上传 dist 目录:
      ossutil cp -r dist oss://my-city-animation
      
    • 配置域名(如 animation.oss-cn-hangzhou.aliyuncs.com)和 CDN 加速。
  • 注意事项
    • 设置 CORS 规则,允许 GET 请求加载模型和纹理。
    • 启用 HTTPS,确保安全性。
    • 使用阿里云 CDN 优化模型加载速度。
3. 优化建议
  • 动画优化:限制动画数量,使用压缩模型。
  • 纹理优化:使用压缩纹理(JPG,<100KB),尺寸为 2 的幂。
  • 性能优化:异步加载模型,减少渲染开销。
  • 可访问性测试:使用 axe DevTools 检查 WCAG 2.1 合规性。
  • 内存管理:清理未使用动画和纹理(mixer.uncacheClip()texture.dispose())。

注意事项

  • 动画管理:确保 AnimationMixer 和 Tween.js 在渲染循环中正确更新。
  • 模型准备:使用 Mixamo 导出 GLB 模型,确保包含动画。
  • WebGL 兼容性:测试主流浏览器(Chrome、Firefox、Safari)。
  • 可访问性:严格遵循 WCAG 2.1,确保 ARIA 属性正确使用。
  • 学习资源
    • Three.js 官方文档:https://threejs.org
    • Tween.js 文档:https://github.com/tweenjs/tween.js
    • Mixamo:https://www.mixamo.com
    • WCAG 2.1 指南:https://www.w3.org/WAI/standards-guidelines/wcag/
    • Tailwind CSS:https://tailwindcss.com
    • Stats.js:https://github.com/mrdoob/stats.js
    • Vite:https://vitejs.dev
    • 阿里云 OSS:https://help.aliyun.com/product/31815.html

总结

本文通过交互式城市角色动画展示案例,详细解析了 Tween.js 和 AnimationMixer 的使用,展示了如何实现 Object3D 属性动画、加载 Mixamo 骨骼动画,以及控制动画播放、暂停和交叉渐变。结合 Vite、TypeScript 和 Tailwind CSS,场景实现了动态交互、可访问性优化和性能监控。测试结果表明动画流畅,WCAG 2.1 合规性确保了包容性。本案例为开发者提供了动画系统实践的基础。

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

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

相关文章

装修进度管理系统功能对比:主流工具9选

本文分享了9款常用的装修进度管理软件&#xff0c;包括&#xff1a;1.Worktile&#xff1b;2.中望软件&#xff1b;3.三维家&#xff1b;4.Procore&#xff1b;5.易达装修管理系统&#xff1b;6.装修管家&#xff1b;7.Zoho Projects&#xff1b;8.中建君联&#xff1b;9.一品装…

深度学习篇---预训练模型

在深度学习中&#xff0c;预训练模型&#xff08;Pretrained Model&#xff09; 是提升开发效率和模型性能的 “利器”。无论是图像识别、自然语言处理还是语音识别&#xff0c;预训练模型都被广泛使用。下面从概念、使用原因、场景、作用等方面详细介绍&#xff0c;并结合 Pyt…

Redis ①⑦-分布式锁

分布式锁 分布式锁是锁的一种&#xff0c;都是为了解决多线程/多进程环境下&#xff0c;对共享资源的访问冲突问题。 不过&#xff0c;像 Java 的 synchronized 或者 C 的 mutex 这种锁&#xff0c;都是进程内的锁&#xff0c;而分布式锁则是跨越进程/机器的锁。也就是可以针对…

OpenCV-图像预处理➀【图像颜色空间转换、灰度化实验、二值化处理、镜像翻转 和 仿射变换】

文章目录先言一、图像颜色空间转换1.RGB颜色空间2.颜色加法3.颜色加权加法4.HSV颜色空间5.图像转换&#xff08;cvtColor()&#xff09;二、灰度实验1.灰度图2.图像灰度化&#xff08;最大值法&#xff09;3.图像灰度化&#xff08;平均值法&#xff09;4.图像灰度化&#xff0…

APP逆向 day9 安卓开发基础

一.前言 app逆向当然要学安卓基础啦&#xff01;今天我们来教安卓基础当然&#xff0c;安卓基础不会教的很多&#xff0c;比java还要少&#xff0c;还是那句话&#xff0c;了解就好。 二.安卓环境搭建 2.1 安卓介绍 如果做安卓开发 需要会java代码安卓SDK(安卓提供的内置…

Jmeter的元件使用介绍:(三)配置元件详解02

六、计数器 可以用来做一些变量自增操作。 1、Starting value:定义初始值 2、递增&#xff1a;定义每次执行递增多少 3、Maximum value:定义承受的最大值 4、数据格式&#xff1a;可以不填&#xff0c;也可以定义成000;001;002等等任意格式都行。&#xff08;1&#xff09;如…

JavaWeb学习打卡15(JSP标签、JSTL标签、EL表达式)

EL表达式&#xff1a;${ }获取数据执行运算获取web开发的常用对象在pom.xml 文件中导入JSP、JSTL相关依赖&#xff1a;<!--JSP依赖--><!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --><dependency><groupId>java…

7.22数据结构——顺序表

文章目录一、思维导图二、实现顺序表的功能代码head.htest.cmain.c一、思维导图 二、实现顺序表的功能代码 head.h #ifndef __HEAD_H__ #define __HEAD_H__#include <stdio.h> #include <string.h> #include <stdlib.h> //数组的最大长度 #define MAXSIZE …

【如何无限制免费试用 IDEA || Pycharm(JB 全家桶)】

如何无限制免费试用 IDEA || Pycharm(JB 全家桶) 一、目标:解决 JB 全家桶试用时长痛点 如果你是程序员,大概率用过 JetBrains 家的 IDE——IDEA 写 Java、Pycharm 写 Python、WebStorm 做前端,体验确实顶流,但官方 30 天试用到期后,动辄几千的年费实在让人肉痛。 咱…

Qt(资源库和按钮组)

这一节是对上一节的补充&#xff0c;上一节提到QLabel类和QAabstractButton类&#xff0c;这节内容&#xff1a;1.如设置资源库&#xff0c;使用资源设置图片2. 使用按钮组管理多个按钮。一、资源库1. 资源库作用Qt的资源库&#xff08;Resource System&#xff0c;.qrc文件&am…

一道检验编码能力的字符串的题目

#include<iostream> #include<vector> #include<string> using namespace std; int bNum0,gNum0; int findEnd(string& s,int si){int lens.size();//当前字母在哪个字符串中,存入comp中string comp;if(s[si]b||s[si]o||s[si]y){comp"boy";bNu…

UniApp X 网络请求避坑指南:从 JS 到 UTS 的 JSON 数据处理全解析

在 UniApp 开发中&#xff0c;我们经常需要通过 uni.request 获取服务器返回的 JSON 数据&#xff0c;并将其绑定到页面或进行逻辑处理。但在 UniApp X&#xff08;基于 UTS&#xff09; 中&#xff0c;由于引入了 强类型语言特性&#xff0c;处理 JSON 数据的方式与 JS 有明显…

iOS 网络请求常用依赖库与系统自带 API 介绍与示例

iOS 网络请求常用依赖库与系统自带 API 介绍与示例 在 iOS 开发中&#xff0c;进行网络请求是几乎所有应用都不可或缺的功能。开发者有多种选择来处理网络通信&#xff0c;从系统自带的 URLSession 到各种流行的第三方库。下面我将为您介绍 URLSession、AFNetworking、Alamofir…

JavaScript 中 let 在循环中的作用域机制解析

一、let在循环中的特殊性 let作为ES6引入的块级作用域声明&#xff0c;在循环结构中存在特殊行为&#xff0c;其核心区别于var的函数作用域特性。理解这一特性对于编写正确的闭包逻辑至关重要。 在 ECMAScript 规范里&#xff0c;let声明的变量具有块级作用域特性&#xff0c;这…

@Subscribe@AllowConcurrentEvents解析这两个注解

@Subscribe@AllowConcurrentEvents解析这两个注解 @Subscribe 和 @AllowConcurrentEvents 是 Guava EventBus(Google 开源的事件总线框架)中用于处理事件订阅的注解,主要用于实现组件间的解耦通信。下面分别解析: 1. @Subscribe 注解 作用:标记一个方法为事件订阅者方法,…

好看的小程序推广单页HTML源码 可用作导航页

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 响应式的小程序推广单页HTML源码。这个设计采用了现代化的UI元素&#xff0c;包含吸引人的标题、特性展示、二维码区域和行动号召按钮。 二、效果展示 1.部分代码 代码如下&#xff0…

华为仓颉编程语言实践体验

华为仓颉编程语言实践体验 目前华为仓颉编程语言因为其推出时间较短&#xff0c;生态系统不完善。官网资料权威&#xff0c;但比较庞大难懂。快速实验入门&#xff0c;是学习一门编程语言的法宝。网上靠谱的资料稀少&#xff0c;特此撰文介绍&#xff0c;帮助初学者减少挫折感&…

YOLOv11实战,使用YOLOv11训练自己的数据集和推理(附YOLOv11网络结构图)

2024年计算机视觉领域的颠覆性突破,YOLOv11以22%的参数量减少和0.3%的mAP提升重新定义实时目标检测的边界 本文将手把手带你完成YOLOv11的全流程实战,包含环境配置、数据准备、模型训练、推理部署及创新优化方案,并深度解析其网络架构设计思想。 一、YOLOv11核心创新解析 …

macOS xcode打包ios测试ipa应用包

可以参考&#xff1a; https://blog.csdn.net/sinat_34104446/article/details/133684756 过程中遇到很多稀奇古怪的报错&#xff0c;基本重启电脑即可解决。。。在我按照上面的步骤申请并导入新证书后&#xff0c;还遇到了一个问题&#xff1a;解决办法&#xff1a; https://b…

STM32基础知识学习笔记:ICODE、DCODE、DMA等常见名词的解释

基于AI生成内容。 ICODEICODE&#xff1a;指令总线&#xff08;Instruction Bus&#xff09; 主要用于处理 CPU 对程序指令的读取操作。它是 STM32 存储架构中重要的组成部分&#xff0c;与数据总线&#xff08;DCODE&#xff09;、系统总线&#xff08;System Bus&#xff09;…