大屏自适应
核心是使用css的transform中的scale进行缩放以自适应,而缩放比例的计算需要确定一个基准,例如1920*1080:
const getScale = useCallback(() => {
const ww = document.documentElement.clientWidth / 1920;
const wh = document.documentElement.clientHeight / 1080;
return ww < wh ? ww : wh;
}, []);
然后设置好resize的监听事件,以及对应样式就好:
const demoKanBan = () => {
const [scale, setScale] = useState();
// 页面初始化执行
useEffect(() => {
changeSize();
window.addEventListener('resize', changeSize);
}, []);
// 大屏缩放比例
const getScale = useCallback(() => {
const ww = document.documentElement.clientWidth / 1920;
const wh = document.documentElement.clientHeight / 1080;
return ww < wh ? ww : wh;
}, []);
// 防抖动
const changeSize = debounce(() => {
const s = getScale();
setScale(s);
}, 500);
return (
{/* 看板内容 */}
);
};
截图如下:
3D旋转
让物体旋转起来,本质就是让它在进行x轴运动的同时,y轴也在运动,我们假定一个运动周期是20s,由于我们可以设置成交替的模式,所以动画的时长就是一半,10s。
我们先来介绍下css的animation这一属性,它是由六个子属性组成的,即:
- animation-name(动画名称、一般我们设置关键帧即可)
- animation-duration(定义动画完成一个周期所需要的时间)
- animation-timing-function(规定动画的速度曲线)
- animation-delay(定义动画何时开始,定义为负值的话可以使动画跳过指定时间)
- animation-iteration-count(定义动画的播放次数)
- animation-direction(定义是否应该轮流反向播放动画)
所以我们先定义相关的关键帧:
// x轴
@keyframes animX {
0% {left: 0%;}
100% {left: 90%;}
}
// y轴
@keyframes animY {
0% {top: 0%;}
100% {top: 80%;}
}
然后定义动画即可(多个动画可以','分隔)
.element1 {
animation: animX 10s cubic-bezier(0.36, 0, 0.64, 1) -5s infinite alternate,
animY 10s cubic-bezier(0.36, 0, 0.64, 1) 0s infinite alternate,
}
当然,要实现多个动画元素一起运动的效果,在这个例子里我们主要是控制animation-delay这一属性,比如上面的x轴动画是直接从第5s开始,y轴动画则是从0开始,我们可以依次类推接下来所要出现的动画元素初始的位置,如果我们想要n个球一起旋转,那么后一个球只需要在前一个球的基础上分别跳过 动画总时长/n 秒即可;
比如说上面我们定义的动画总时长是20s,10个元素一起旋转,那么从第一个元素往后开始,每个元素的延迟时间都要增加2s,element2的延时时间为-7s、-2s,element3的延迟时间为-9s,-4s,以此类推。
最后的效果如下图:
Three.js
three.js是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能。
在react中进行three.js的开发,通过查找相关资料,@react-three/fiber这一个包使用可重用、自包含的组件以声明方式构建场景,这些组件可以对状态做出反应,易于交互,并可以进入react的生态系统。而@react-three/drei则是three.js的一些预先制作好的功能的集合。
我们可以先添加这两个包和three.js:
yarn add three @react-three/fiber @react-three/drei
下面是一些概念:
Canvas标签
这个Canvas是定义 React Three Fiber 场景的地方,有点像Three.js中的:
const scene = new THREE.Scene();
注意,Canvas标签首字母大写,且需要从@react-three/fiber中引入,而其它的大部分标签都已经被注入,可以直接使用。
import { Canvas } from '@react-three/fiber';
mesh标签
相当于Three.js中的网格:
new THREE.Mesh( geometry, material );
只是其相关属性的定义可以写在标签体内,比如缩放和旋转就可以这样子定义:
ambientLight标签
相当于Three.js中的环境光:
const light = new THREE.AmbientLight( color : Integer, intensity : Float);
同样的,现在传入的参数可以作为相关属性定义在标签体内:
directionalLight标签
相当于Three.js中的平行光:
const directionalLight = new THREE.DirectionalLight( color : Integer, intensity : Float );
同样的,现在传入的参数可以作为相关属性定义在标签体内:
OrbitControls标签
相当于Three.js中的轨道控制器:
const controls = new OrbitControls( camera, renderer.domElement );
需要从@react-three/drei中引入,使用时直接:
import { OrbitControls } from "@react-three/drei";
导入3d模型
可以去网站https://sketchfab.com/下载相关3d模型,使用原始的Three.js加载3d模型,方法是:
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load( 'path/to/model.glb', function ( gltf ) {
scene.add( gltf.scene );
}, undefined, function ( error ) {
console.error( error );
});
现在我们使用另一种方式来引入GLTF文件,使用一种工具:gltf-pipeline
gltf-pipeline由Richard Lee和Cesium团队用来优化glTF的工具。
将glTF转换为glb(并反向)
将缓冲区/纹理保存为嵌入文件或单独文件
将glTF 1.0模型转换为glTF 2.0
应用Draco网格压缩
1.安装:
yarn add global gltf-pipeline
2.将 glTF 转换为 Draco glTF。通过终端进入到3d模型的目录下,在终端输入以下命令:
gltf-pipeline -i scene.gltf -o yourName.gltf -d
然后就会在当前目录下生成 yourName.gltf 这一文件
3.生成js文件
npx gltfjsx yourName.gltf
就会在当前目录下生成yourName.js这一文件,这便是通过这个工具进行操作后生成的可嵌入的一个3D模型;
然后我们把这两个文件放入项目中,注意,由于生成的yourName.js中引入gltf默认是
const { nodes, materials } = useGLTF('/xxx.gltf')
所以我们需要把gltf文件放到项目根目录下的publi文件夹下面,然后在需要使用到模型的地方引入这个js文件即可:
import Car from "./Car.js";
import { Suspense } from "react";
完整的一个通过@react-three/fiber辅助创建的Three.js示例代码如下:
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from "@react-three/drei";
import React, { Suspense } from "react";
import Car from "./Car.js";
const ThreeTest = () => {
return (
);
};
export default ThreeTest;