当前位置: 首页 > news >正文

Vue3 + threeJs 定义六种banner轮播图切换动画效果:百叶窗、手风琴、拼图、渐变、菱形波次、圆形扩展

最近写了一个案例。用来丰富banner图的切换效果,css不是特别完美,所以采用的事threeJs的方式:
vue3 + threeJS
动画效果有:百叶窗、手风琴、拼图、渐变、菱形波次、圆形扩展动画:
以下是动画效果视频:

threeJS写banner切换效果(六个动画效果)

代码中已经做好了优化:
(1)窗口大小调整时更新渲染器和相机;
(2)浏览器切换到其他网页时,关闭定时器;浏览器切换回当前网页时,重新开始轮播。
(3)切换路由或组件卸载时调用,确保轮播定时器被清理。
(4)渲染采用ShaderMaterial材质:可以用于全屏显示图片,适用于轮播图、背景等场景,显示效果非常锐利、高清
(5)代码中注释清晰

  • 整体逻辑
    1. 初始化场景、相机、渲染器。
    1. 加载三张图片纹理,并设置纹理参数。
    1. 定义六种动画效果:百叶窗、手风琴、拼图、渐变、菱形波次、圆形扩展。
    1. 使用 setTimeout 控制每个效果的切换时间。
    1. 使用 effectIndex 来控制当前使用的特效。
    1. 使用 currentIndex 来控制当前显示的图片索引。
    1. 使用 isFirstLoad 来判断是否是第一次加载,如果是,则直接显示第一张图片。
    1. 每次切换效果时,先加载下一张图片的纹理,然后根据当前效果索引调用对应的动画函数。
    1. 每个效果动画完成后,更新 currentFullMesh,并在最后一个效果后延时8000毫秒再开始下一轮。
    1. 使用 requestAnimationFrame 实现渲染循环。
    1. 使用 THREE.js 的 PlaneGeometry 和 ShaderMaterial 实现全屏高清效果。
    1. 使用 THREE.js 的 TextureLoader 加载图片纹理,并设置纹理的编码、包裹方式和过滤方式。
    1. 使用 THREE.js 的 PerspectiveCamera 实现透视相机。
    1. 使用 THREE.js 的 WebGLRenderer 实现渲染器,并设置输出编码和色调映射。

以下是完整代码:

<template><div><div class="banner_box" ref="bannerBox"></div></div>
</template><script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as THREE from "three";
import bannerImage1 from "../src/assets/img/banner1.png";
import bannerImage2 from "../src/assets/img/banner2.png";
import bannerImage3 from "../src/assets/img/banner3.png";const bannerBox = ref(null);/*** 工具函数:全屏高清ShaderMaterial,支持透明度渐变:* * 创建一个全屏的ShaderMaterial,用于显示纹理。* * 该材质支持透明度渐变,可以通过 uniforms 控制纹理和透明度。* * 使用 THREE.js 的 PlaneGeometry 实现全屏效果。* * 使用顶点着色器和片段着色器实现纹理的显示和透明度控制。
ShaderMaterial 默认会用纹理的原始分辨率和采样方式,且不会自动做 mipmap 或滤波降级,显示效果非常锐利、高清。
相较于MeshBasicMaterial,ShaderMaterial 提供了更高的灵活性和控制力,
MeshBasicMaterial会出现模糊或锯齿现象,尤其是在全屏显示时。* * 该ShaderMaterial材质可以用于全屏显示图片,适用于轮播图、背景等场景。* */
function createFullScreenShaderMaterial(texture, opacity = 1.0) {return new THREE.ShaderMaterial({uniforms: {uTexture: { value: texture },uOpacity: { value: opacity },},vertexShader: `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);}`,fragmentShader: `uniform sampler2D uTexture;uniform float uOpacity;varying vec2 vUv;void main() {vec4 color = texture2D(uTexture, vUv);color.a *= uOpacity;gl_FragColor = color;}`,transparent: true,});
}
// 定义轮播相关变量
let slideshowTimeout = null;
let animationFrameId = null;
onMounted(() => {/*** 整体逻辑:* 1. 初始化场景、相机、渲染器。* 2. 加载三张图片纹理,并设置纹理参数。* 3. 定义六种动画效果:百叶窗、手风琴、拼图、渐变、菱形波次、圆形扩展。* 4. 使用 setTimeout 控制每个效果的切换时间。* 5. 使用 effectIndex 来控制当前使用的特效。* 6. 使用 currentIndex 来控制当前显示的图片索引。* 7. 使用 isFirstLoad 来判断是否是第一次加载,如果是,则直接显示第一张图片。* 8. 每次切换效果时,先加载下一张图片的纹理,然后根据当前效果索引调用对应的动画函数。* 9. 每个效果动画完成后,更新 currentFullMesh,并在最后一个效果后延时8000毫秒再开始下一轮。* 10. 使用 requestAnimationFrame 实现渲染循环。* 11. 使用 THREE.js 的 PlaneGeometry 和 ShaderMaterial 实现全屏高清效果。* 12. 使用 THREE.js 的 TextureLoader 加载图片纹理,并设置纹理的编码、包裹方式和过滤方式。* 13. 使用 THREE.js 的 PerspectiveCamera 实现透视相机。* 14. 使用 THREE.js 的 WebGLRenderer 实现渲染器,并设置输出编码和色调映射。* */// 初始化场景、相机、渲染器const scene = new THREE.Scene();// 获取 bannerBox 的宽高const bannerWidth = bannerBox.value.clientWidth;const bannerHeight = bannerBox.value.clientHeight;// 初始化相机// 使用透视相机,视野角度为75度,宽高比为 bannerWidth / bannerHeight,近裁剪面为0.1,远裁剪面为1000const camera = new THREE.PerspectiveCamera(75,bannerWidth / bannerHeight,0.1,1000);// 设置相机位置,使其能够完整看到整个 banner// 相机位置设置为 bannerHeight / (2 * Math.tan((camera.fov * Math.PI) / 360))camera.position.z =bannerHeight / (2 * Math.tan((camera.fov * Math.PI) / 360));// 设置渲染器const renderer = new THREE.WebGLRenderer();renderer.setSize(bannerWidth, bannerHeight);renderer.outputEncoding = THREE.sRGBEncoding;renderer.toneMapping = THREE.ACESFilmicToneMapping;renderer.toneMappingExposure = 0.9;bannerBox.value.appendChild(renderer.domElement);// 加载图片纹理const textureLoader = new THREE.TextureLoader();const textures = [textureLoader.load(bannerImage1),textureLoader.load(bannerImage2),textureLoader.load(bannerImage3),];textures.forEach((texture) => {texture.encoding = THREE.sRGBEncoding;texture.wrapS = THREE.ClampToEdgeWrapping;texture.wrapT = THREE.ClampToEdgeWrapping;texture.minFilter = THREE.LinearFilter;});let currentFullMesh = null;/*** 百叶窗动画:* 效果:将整个纹理分割成 5 个水平的百叶窗片段,* 每个片段从上到下依次展开,形成百叶窗效果。* */function animateBlinds(nextTexture, onComplete) {const blinds = [];const blindsCount = 5;const blindHeight = bannerHeight / blindsCount;for (let i = 0; i < blindsCount; i++) {const geometry = new THREE.PlaneGeometry(bannerWidth, blindHeight);const material = createFullScreenShaderMaterial(textures[currentIndex],0);material.transparent = true;// 设置材质的 uniformsconst uvOffsetY = 1 - (i + 1) / blindsCount;const uvOffsetHeight = 1 / blindsCount;const uvArray = geometry.attributes.uv.array;uvArray[1] = uvOffsetY + uvOffsetHeight;uvArray[3] = uvOffsetY + uvOffsetHeight;uvArray[5] = uvOffsetY;uvArray[7] = uvOffsetY;geometry.attributes.uv.needsUpdate = true;// 创建材质const mesh = new THREE.Mesh(geometry, material);mesh.position.y = bannerHeight / 2 - blindHeight / 2 - i * blindHeight;scene.add(mesh);blinds.push(mesh);}// 设置每个百叶窗片段的纹理和透明度blinds.forEach((blind, index) => {setTimeout(() => {blind.material.uniforms.uTexture.value = nextTexture;blind.material.needsUpdate = true;let progress = 0;const duration = 500;function fadeIn() {progress += 16;const t = Math.min(progress / duration, 1);blind.material.uniforms.uOpacity.value = t;if (t < 1) {requestAnimationFrame(fadeIn);}}fadeIn();}, index * 300);});// 所有百叶窗片段动画完成后,移除它们并显示下一张图片setTimeout(() => {blinds.forEach((mesh) => scene.remove(mesh));if (currentFullMesh) scene.remove(currentFullMesh);const geometry = new THREE.PlaneGeometry(bannerWidth, bannerHeight);const material = createFullScreenShaderMaterial(nextTexture, 1);const mesh = new THREE.Mesh(geometry, material);scene.add(mesh);currentFullMesh = mesh;}, blindsCount * 300 + 1000);}/*** 拼图碎片动画:* 效果:将整个纹理分割成 5x5 的拼图碎片,动画整体实现从左上角到右下角的拼图效果,* */function createPuzzleEffect(nextTexture) {const rows = 5;const cols = 5;const pieceWidth = bannerWidth / cols;const pieceHeight = bannerHeight / rows;const pieces = [];const tempGroup = new THREE.Group();scene.add(tempGroup);for (let col = 0; col < cols; col++) {for (let row = 0; row < rows; row++) {// 创建每个拼图碎片的几何体和材质// 使用 PlaneGeometry 创建平面几何体const geometry = new THREE.PlaneGeometry(pieceWidth, pieceHeight);const material = createFullScreenShaderMaterial(nextTexture, 0);// 设置材质的 uniformsconst uvOffsetX = col / cols;const uvOffsetY = 1 - (row + 1) / rows;const uvOffsetWidth = 1 / cols;const uvOffsetHeight = 1 / rows;const uvArray = geometry.attributes.uv.array;uvArray[0] = uvOffsetX;uvArray[1] = uvOffsetY + uvOffsetHeight;uvArray[2] = uvOffsetX + uvOffsetWidth;uvArray[3] = uvOffsetY + uvOffsetHeight;uvArray[4] = uvOffsetX;uvArray[5] = uvOffsetY;uvArray[6] = uvOffsetX + uvOffsetWidth;uvArray[7] = uvOffsetY;geometry.attributes.uv.needsUpdate = true;// 创建每个拼图碎片的网格const mesh = new THREE.Mesh(geometry, material);mesh.position.x = col * pieceWidth - bannerWidth / 2 + pieceWidth / 2;mesh.position.y =bannerHeight / 2 - row * pieceHeight - pieceHeight / 2;tempGroup.add(mesh);pieces.push({ mesh, col, row });}}// 计算最大对角线长度const maxDiagonal = rows + cols - 1;for (let d = 0; d < maxDiagonal; d++) {setTimeout(() => {pieces.forEach(({ mesh, col, row }) => {if (col + row === d) {let progress = 0;const duration = 500;function fadeIn() {progress += 16;const t = Math.min(progress / duration, 1);mesh.material.uniforms.uOpacity.value = t;if (t < 1) {requestAnimationFrame(fadeIn);}}fadeIn();}});}, d * 300);}// 所有拼图碎片动画完成后,移除它们并显示下一张图片setTimeout(() => {scene.remove(tempGroup);if (currentFullMesh) scene.remove(currentFullMesh);const geometry = new THREE.PlaneGeometry(bannerWidth, bannerHeight);const material = createFullScreenShaderMaterial(nextTexture, 1);const mesh = new THREE.Mesh(geometry, material);scene.add(mesh);currentFullMesh = mesh;}, maxDiagonal * 300 + 1000);}/*** 手风琴动画:* 效果:动画整体实现从右到左的手风琴效果,,每一个手风琴片段从下到上展开。* */function createAccordionEffect(nextTexture) {const accordionCount = 5;const accordionWidth = bannerWidth / accordionCount;const accordionHeight = bannerHeight;const accordions = [];for (let i = 0; i < accordionCount; i++) {const geometry = new THREE.PlaneGeometry(accordionWidth, accordionHeight);const uStart = i / accordionCount;const uEnd = (i + 1) / accordionCount;const uvArray = geometry.attributes.uv.array;uvArray[0] = uStart;uvArray[1] = 1;uvArray[2] = uEnd;uvArray[3] = 1;uvArray[4] = uStart;uvArray[5] = 0;uvArray[6] = uEnd;uvArray[7] = 0;geometry.attributes.uv.needsUpdate = true;// 创建每个手风琴片段的材质const material = createFullScreenShaderMaterial(nextTexture, 1);const mesh = new THREE.Mesh(geometry, material);// 设置每个手风琴片段的位置mesh.position.x =i * accordionWidth - bannerWidth / 2 + accordionWidth / 2;mesh.position.y = 0;mesh.scale.y = 0;scene.add(mesh);accordions.push(mesh);}// 动画效果:每个手风琴片段从下到上展开accordions.forEach((accordion, index) => {setTimeout(() => {let progress = 0;const duration = 1200;// 使用 requestAnimationFrame 实现动画function animatePiece() {progress += 16;const t = Math.min(progress / duration, 1);accordion.scale.y = t;accordion.position.y = (t - 1) * (bannerHeight / 2);if (t < 1) {requestAnimationFrame(animatePiece);}}animatePiece();}, (accordionCount - 1 - index) * 300);});// 所有手风琴片段动画完成后,移除它们并显示下一张图片setTimeout(() => {accordions.forEach((mesh) => scene.remove(mesh));if (currentFullMesh) scene.remove(currentFullMesh);const geometry = new THREE.PlaneGeometry(bannerWidth, bannerHeight);const material = createFullScreenShaderMaterial(nextTexture, 1);const mesh = new THREE.Mesh(geometry, material);scene.add(mesh);currentFullMesh = mesh;}, accordionCount * 300 + 1000);}/*** 渐变动画:* 效果:将整个纹理渐变显示,同时实现缩放动画,* */
function createGradientEffect(nextTexture) {const geometry = new THREE.PlaneGeometry(bannerWidth, bannerHeight);const material = createFullScreenShaderMaterial(nextTexture, 0);const mesh = new THREE.Mesh(geometry, material);scene.add(mesh);currentFullMesh = mesh;let progress = 0;const duration = 2000;const startScale = 1.2; // 初始放大倍数const endScale = 1.0;   // 结束时为正常大小function animateGradient() {progress += 16;const t = Math.min(progress / duration, 1);mesh.material.uniforms.uOpacity.value = t;// 图片缩放动画:从 startScale 到 endScaleconst scale = startScale + (endScale - startScale) * t;mesh.scale.set(scale, scale, 1);if (t < 1) {requestAnimationFrame(animateGradient);} else {// 动画结束,重置为正常大小mesh.scale.set(1, 1, 1);if (currentFullMesh) scene.remove(currentFullMesh);const newGeometry = new THREE.PlaneGeometry(bannerWidth, bannerHeight);const newMaterial = createFullScreenShaderMaterial(nextTexture, 1);const newMesh = new THREE.Mesh(newGeometry, newMaterial);scene.add(newMesh);currentFullMesh = newMesh;}}animateGradient();
}/*** 菱形波次效果:* 效果:动画整体实现从中心向外扩散的菱形波次效果,* 每个菱形片段从中心向外扩散,形成菱形波次效果。* */function createDiamondGradientEffect(nextTexture) {const rows = 7;const cols = 5;const pieceWidth = bannerWidth / cols;const pieceHeight = bannerHeight / rows;const pieces = [];const tempGroup = new THREE.Group();scene.add(tempGroup);const centerRow = Math.floor(rows / 2);const centerCol = Math.floor(cols / 2);for (let col = 0; col < cols; col++) {for (let row = 0; row < rows; row++) {const geometry = new THREE.PlaneGeometry(pieceWidth, pieceHeight);const material = createFullScreenShaderMaterial(nextTexture, 0);// 设置材质的 uniformsconst uvOffsetX = col / cols;const uvOffsetY = 1 - (row + 1) / rows;const uvOffsetWidth = 1 / cols;const uvOffsetHeight = 1 / rows;const uvArray = geometry.attributes.uv.array;uvArray[0] = uvOffsetX;uvArray[1] = uvOffsetY + uvOffsetHeight;uvArray[2] = uvOffsetX + uvOffsetWidth;uvArray[3] = uvOffsetY + uvOffsetHeight;uvArray[4] = uvOffsetX;uvArray[5] = uvOffsetY;uvArray[6] = uvOffsetX + uvOffsetWidth;uvArray[7] = uvOffsetY;geometry.attributes.uv.needsUpdate = true;const mesh = new THREE.Mesh(geometry, material);mesh.position.x = col * pieceWidth - bannerWidth / 2 + pieceWidth / 2;mesh.position.y =bannerHeight / 2 - row * pieceHeight - pieceHeight / 2;tempGroup.add(mesh);const distance = Math.abs(row - centerRow) + Math.abs(col - centerCol);pieces.push({ mesh, distance });}}// 计算最大距离const maxDistance = Math.max(...pieces.map((p) => p.distance));// 使用 setTimeout 控制每个菱形片段的动画for (let d = 0; d <= maxDistance; d++) {setTimeout(() => {pieces.forEach(({ mesh, distance }) => {if (distance === d) {let progress = 0;const duration = 400;function fadeIn() {progress += 16;const t = Math.min(progress / duration, 1);mesh.material.uniforms.uOpacity.value = t;if (t < 1) {requestAnimationFrame(fadeIn);}}fadeIn();}});}, d * 200);}// 所有菱形片段动画完成后,移除它们并显示下一张图片setTimeout(() => {scene.remove(tempGroup);if (currentFullMesh) scene.remove(currentFullMesh);const geometry = new THREE.PlaneGeometry(bannerWidth, bannerHeight);const material = createFullScreenShaderMaterial(nextTexture, 1);const mesh = new THREE.Mesh(geometry, material);scene.add(mesh);currentFullMesh = mesh;}, (maxDistance + 1) * 200 + 800);}/*** 圆形扩展动画:* 效果:圆形从左上角开始扩展,直到覆盖整个纹理,* */function revealPixels(nextTexture) {const geometry = new THREE.PlaneGeometry(bannerWidth, bannerHeight);// 创建 uniformsconst uniforms = {uTexture: { value: nextTexture },uResolution: { value: new THREE.Vector2(bannerWidth, bannerHeight) },uRadius: { value: 0.0 },};// 创建 ShaderMaterialconst material = new THREE.ShaderMaterial({uniforms,transparent: true,vertexShader: `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);}`,fragmentShader: `uniform sampler2D uTexture;uniform vec2 uResolution;uniform float uRadius;varying vec2 vUv;void main() {vec2 uv = vUv;vec2 pixelPos = uv * uResolution;float dist = length(pixelPos - vec2(0.0, uResolution.y));float alpha = smoothstep(uRadius - 10.0, uRadius, dist);vec4 color = texture2D(uTexture, uv);color.a *= 1.0 - alpha;gl_FragColor = color;}`,});// 创建网格并添加到场景const mesh = new THREE.Mesh(geometry, material);scene.add(mesh);// 设置当前全屏网格let progress = 0;const duration = 2000;const maxRadius = Math.sqrt(bannerWidth * bannerWidth + bannerHeight * bannerHeight);// 动画函数:使用 requestAnimationFrame 实现圆形扩展动画function animateReveal() {progress += 16;const t = Math.min(progress / duration, 1);uniforms.uRadius.value = t * maxRadius;if (t < 1) {requestAnimationFrame(animateReveal);} else {if (currentFullMesh) scene.remove(currentFullMesh);scene.remove(mesh);const geometry2 = new THREE.PlaneGeometry(bannerWidth, bannerHeight);const material2 = createFullScreenShaderMaterial(nextTexture, 1);const mesh2 = new THREE.Mesh(geometry2, material2);scene.add(mesh2);currentFullMesh = mesh2;}}animateReveal();}/*** 轮播逻辑:动画效果有:百叶窗、手风琴、拼图、渐变、菱形波次、圆形扩展动画。* 每次切换效果时,先加载下一张图片的纹理,* 如果是第一次加载,则直接显示第一张图片。* 然后根据当前效果索引调用对应的动画函数。* 每个效果动画完成后,更新 currentFullMesh,* 并在最后一个效果后延时8000毫秒再开始下一轮。* 使用 setTimeout 控制每个效果的切换时间。* 使用 effectIndex 来控制当前使用的特效。* 使用 currentIndex 来控制当前显示的图片索引。* 使用 isFirstLoad 来判断是否是第一次加载,* */let currentIndex = 0;let effectIndex = 0;let isFirstLoad = true;// 开始轮播function startSlideshow() {const nextIndex = (currentIndex + 1) % textures.length;if (isFirstLoad) {const material = createFullScreenShaderMaterial(textures[currentIndex],1);const geometry = new THREE.PlaneGeometry(bannerWidth, bannerHeight);const mesh = new THREE.Mesh(geometry, material);scene.add(mesh);currentFullMesh = mesh;isFirstLoad = false;setTimeout(startSlideshow, 2000);return;}if (effectIndex === 0) {animateBlinds(textures[nextIndex]);} else if (effectIndex === 1) {createAccordionEffect(textures[nextIndex]);} else if (effectIndex === 2) {createPuzzleEffect(textures[nextIndex]);} else if (effectIndex === 3) {createGradientEffect(textures[nextIndex]);} else if (effectIndex === 4) {createDiamondGradientEffect(textures[nextIndex]);} else if (effectIndex === 5) {revealPixels(textures[nextIndex]);}effectIndex = (effectIndex + 1) % 6;// 更新 currentIndexcurrentIndex = nextIndex;slideshowTimeout = setTimeout(startSlideshow, 5000);}function animate() {animationFrameId = requestAnimationFrame(animate);renderer.render(scene, camera);}startSlideshow();animate();// 窗口大小调整时更新渲染器和相机window.addEventListener("resize", () => {const newWidth = bannerBox.value.clientWidth;const newHeight = bannerBox.value.clientHeight;camera.aspect = newWidth / newHeight;camera.updateProjectionMatrix();renderer.setSize(newWidth, newHeight);// 更新平面几何体的宽高if (currentFullMesh) {currentFullMesh.geometry.dispose(); // 销毁旧几何体const newGeometry = new THREE.PlaneGeometry(newWidth, newHeight);currentFullMesh.geometry = newGeometry; // 替换为新几何体}});// 浏览器切换到其他网页时,关闭定时器window.addEventListener("blur", () => {console.log("浏览器失去焦点,清理定时器");stopSlideshow();});// 浏览器切换回当前网页时,重新开始轮播window.addEventListener("focus", () => {console.log("浏览器获得焦点,重新开始轮播");if (!slideshowTimeout) {startSlideshow();}});
});
// 轮播定时器控制函数
// stopSlideshow 函数可在任何需要时调用,确保定时器被清理。
function stopSlideshow() {if (slideshowTimeout) {clearTimeout(slideshowTimeout);slideshowTimeout = null;}
}// onUnmounted:切换路由或组件卸载时调用,确保轮播定时器被清理。
// 这样可以保证组件卸载时动画和定时器被正确清理,回来时动画不会乱。
onUnmounted(() => {console.log("组件卸载,清理定时器和动画帧");stopSlideshow(); // 停止轮播定时器if (animationFrameId) {cancelAnimationFrame(animationFrameId);animationFrameId = null;}
});
</script><style scoped>
.banner_box {width: 1100px;margin: 0 auto;height: 750px;position: relative;overflow: hidden;
}
</style>
http://www.xdnf.cn/news/913501.html

相关文章:

  • 如何利用 Redis 实现跨多个无状态服务实例的会话共享?
  • 讲解:Java I/O 流体系,并举例每个类的使用
  • 【YOLOs-CPP-图像分类部署】05-OpenVino加速
  • URL 带有 /../ 导致可以访问其他目录--路径穿越问题
  • SON.stringify()和JSON.parse()之间的转换
  • 优化电脑的磁盘和驱动器提高电脑性能和延长硬盘寿命?
  • Unity3D仿星露谷物语开发60之定制角色其他部位
  • Jpackage
  • 信号电压高,传输稳定性变强,但是传输速率下降?
  • Window Server 2019--11 虚拟专用网络
  • 软件测试python学习
  • 第十届电子技术和信息科学国际学术会议(ICETIS 2025)
  • 如何选择正确的团队交互模式:协作、服务还是促进?
  • 【普及+/提高】洛谷P2114 ——[NOI2014] 起床困难综合症
  • 耦合和内聚
  • BECKHOFF(倍福)PLC --北尔HMI ADS Symbolc 通讯
  • 电动螺丝刀-多实体拆图建模案例
  • 全球数控金属切削机床市场:现状、趋势与应对策略
  • # 从底层架构到应用实践:为何部分大模型在越狱攻击下失守?
  • 2025/6/6—halcon知识点总结
  • 高精度加减乘除
  • 艾体宝案例丨Transavia如何借助LambdaTest测试平台高效起飞?
  • 阿里联合上海AI Lab提出DMM!多个模型压缩成一个通用T2I模型!可控任意风格生成!
  • PSpice软件快速入门系列--08.如何进行PSpice AA灵敏度分析
  • 轻松备份和恢复 Android 系统 | 4 种解决方案
  • 【Linux】ls 命令详解及使用示例:列出目录中的内容
  • 【动手学MCP从0到1】2.5 MCP中的Context日志输出、进度汇报和服务端调用客户端的大模型项目实现步骤详解
  • MultipartFile
  • Date类型时间比较
  • 亚马逊跨境:亚马逊优惠券新规和促销机制大改后的定价策略