大屏自適應(yīng)
核心是使用css的transform中的scale進(jìn)行縮放以自適應(yīng)紧索,而縮放比例的計(jì)算需要確定一個(gè)基準(zhǔn)淤袜,例如1920*1080:
const getScale = useCallback(() => {
const ww = document.documentElement.clientWidth / 1920;
const wh = document.documentElement.clientHeight / 1080;
return ww < wh ? ww : wh;
}, []);
然后設(shè)置好resize的監(jiān)聽(tīng)事件踱讨,以及對(duì)應(yīng)樣式就好:
const demoKanBan = () => {
const [scale, setScale] = useState();
// 頁(yè)面初始化執(zhí)行
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;
}, []);
// 防抖動(dòng)
const changeSize = debounce(() => {
const s = getScale();
setScale(s);
}, 500);
return (
<div
style={{
width: '100%',
height: '100%',
position: 'relative',
backgroundColor: 'black',
}}
>
<div
style={{
transform: `scale(${scale}) translate(-50%, -50%)`,
WebkitTransform: `scale(${scale}) translate(-50%, -50%)`,
width: `1920px`,
height: `1080px`,
transformOrigin: '0 0',
position: 'absolute',
left: '50%',
top: '50%',
transition: '0.3s',
}}
>
{/* 看板內(nèi)容 */}
</div>
</div>
);
};
截圖如下:
3D旋轉(zhuǎn)
讓物體旋轉(zhuǎn)起來(lái)峭梳,本質(zhì)就是讓它在進(jìn)行x軸運(yùn)動(dòng)的同時(shí)碾篡,y軸也在運(yùn)動(dòng)虱而,我們假定一個(gè)運(yùn)動(dòng)周期是20s,由于我們可以設(shè)置成交替的模式开泽,所以動(dòng)畫(huà)的時(shí)長(zhǎng)就是一半牡拇,10s。
我們先來(lái)介紹下css的animation這一屬性穆律,它是由六個(gè)子屬性組成的惠呼,即:
- animation-name(動(dòng)畫(huà)名稱(chēng)、一般我們?cè)O(shè)置關(guān)鍵幀即可)
- animation-duration(定義動(dòng)畫(huà)完成一個(gè)周期所需要的時(shí)間)
- animation-timing-function(規(guī)定動(dòng)畫(huà)的速度曲線)
- animation-delay(定義動(dòng)畫(huà)何時(shí)開(kāi)始峦耘,定義為負(fù)值的話可以使動(dòng)畫(huà)跳過(guò)指定時(shí)間)
- animation-iteration-count(定義動(dòng)畫(huà)的播放次數(shù))
- animation-direction(定義是否應(yīng)該輪流反向播放動(dòng)畫(huà))
所以我們先定義相關(guān)的關(guān)鍵幀:
// x軸
@keyframes animX {
0% {left: 0%;}
100% {left: 90%;}
}
// y軸
@keyframes animY {
0% {top: 0%;}
100% {top: 80%;}
}
然后定義動(dòng)畫(huà)即可(多個(gè)動(dòng)畫(huà)可以','分隔)
.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,
}
當(dāng)然剔蹋,要實(shí)現(xiàn)多個(gè)動(dòng)畫(huà)元素一起運(yùn)動(dòng)的效果,在這個(gè)例子里我們主要是控制animation-delay這一屬性辅髓,比如上面的x軸動(dòng)畫(huà)是直接從第5s開(kāi)始泣崩,y軸動(dòng)畫(huà)則是從0開(kāi)始,我們可以依次類(lèi)推接下來(lái)所要出現(xiàn)的動(dòng)畫(huà)元素初始的位置洛口,如果我們想要n個(gè)球一起旋轉(zhuǎn)矫付,那么后一個(gè)球只需要在前一個(gè)球的基礎(chǔ)上分別跳過(guò) 動(dòng)畫(huà)總時(shí)長(zhǎng)/n 秒即可;
比如說(shuō)上面我們定義的動(dòng)畫(huà)總時(shí)長(zhǎng)是20s第焰,10個(gè)元素一起旋轉(zhuǎn)买优,那么從第一個(gè)元素往后開(kāi)始,每個(gè)元素的延遲時(shí)間都要增加2s,element2的延時(shí)時(shí)間為-7s杀赢、-2s烘跺,element3的延遲時(shí)間為-9s,-4s葵陵,以此類(lèi)推液荸。
最后的效果如下圖:
Three.js
three.js是JavaScript編寫(xiě)的WebGL第三方庫(kù)。提供了非常多的3D顯示功能脱篙。
在react中進(jìn)行three.js的開(kāi)發(fā)娇钱,通過(guò)查找相關(guān)資料,@react-three/fiber這一個(gè)包使用可重用绊困、自包含的組件以聲明方式構(gòu)建場(chǎng)景文搂,這些組件可以對(duì)狀態(tài)做出反應(yīng),易于交互秤朗,并可以進(jìn)入react的生態(tài)系統(tǒng)煤蹭。而@react-three/drei則是three.js的一些預(yù)先制作好的功能的集合。
我們可以先添加這兩個(gè)包和three.js:
yarn add three @react-three/fiber @react-three/drei
下面是一些概念:
Canvas標(biāo)簽
這個(gè)Canvas是定義 React Three Fiber 場(chǎng)景的地方取视,有點(diǎn)像Three.js中的:
const scene = new THREE.Scene();
注意硝皂,Canvas標(biāo)簽首字母大寫(xiě),且需要從@react-three/fiber中引入作谭,而其它的大部分標(biāo)簽都已經(jīng)被注入稽物,可以直接使用。
import { Canvas } from '@react-three/fiber';
<Canvas>
{/* content */}
</Canvas>
mesh標(biāo)簽
相當(dāng)于Three.js中的網(wǎng)格:
new THREE.Mesh( geometry, material );
只是其相關(guān)屬性的定義可以寫(xiě)在標(biāo)簽體內(nèi)折欠,比如縮放和旋轉(zhuǎn)就可以這樣子定義:
<mesh
scale={3}
rotation={[0, Math.PI / 2, 0]}
>
</mesh>
ambientLight標(biāo)簽
相當(dāng)于Three.js中的環(huán)境光:
const light = new THREE.AmbientLight( color : Integer, intensity : Float);
同樣的贝或,現(xiàn)在傳入的參數(shù)可以作為相關(guān)屬性定義在標(biāo)簽體內(nèi):
<ambientLight intensity={intensity} color={color} />
directionalLight標(biāo)簽
相當(dāng)于Three.js中的平行光:
const directionalLight = new THREE.DirectionalLight( color : Integer, intensity : Float );
同樣的,現(xiàn)在傳入的參數(shù)可以作為相關(guān)屬性定義在標(biāo)簽體內(nèi):
<directionalLight intensity={intensity} color={color} position={position} />
OrbitControls標(biāo)簽
相當(dāng)于Three.js中的軌道控制器:
const controls = new OrbitControls( camera, renderer.domElement );
需要從@react-three/drei中引入锐秦,使用時(shí)直接:
import { OrbitControls } from "@react-three/drei";
<OrbitControls />
導(dǎo)入3d模型
可以去網(wǎng)站https://sketchfab.com/下載相關(guān)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 );
});
現(xiàn)在我們使用另一種方式來(lái)引入GLTF文件酱床,使用一種工具:gltf-pipeline
gltf-pipeline由Richard Lee和Cesium團(tuán)隊(duì)用來(lái)優(yōu)化glTF的工具羊赵。
將glTF轉(zhuǎn)換為glb(并反向)
將緩沖區(qū)/紋理保存為嵌入文件或單獨(dú)文件
將glTF 1.0模型轉(zhuǎn)換為glTF 2.0
應(yīng)用Draco網(wǎng)格壓縮
1.安裝:
yarn add global gltf-pipeline
2.將 glTF 轉(zhuǎn)換為 Draco glTF。通過(guò)終端進(jìn)入到3d模型的目錄下扇谣,在終端輸入以下命令:
gltf-pipeline -i scene.gltf -o yourName.gltf -d
然后就會(huì)在當(dāng)前目錄下生成 yourName.gltf 這一文件
3.生成js文件
npx gltfjsx yourName.gltf
就會(huì)在當(dāng)前目錄下生成yourName.js這一文件慷垮,這便是通過(guò)這個(gè)工具進(jìn)行操作后生成的可嵌入的一個(gè)3D模型;
然后我們把這兩個(gè)文件放入項(xiàng)目中揍堕,注意,由于生成的yourName.js中引入gltf默認(rèn)是
const { nodes, materials } = useGLTF('/xxx.gltf')
所以我們需要把gltf文件放到項(xiàng)目根目錄下的publi文件夾下面汤纸,然后在需要使用到模型的地方引入這個(gè)js文件即可:
import Car from "./Car.js";
import { Suspense } from "react";
<Suspense fallback={null}>
<Car />
</Suspense>
完整的一個(gè)通過(guò)@react-three/fiber輔助創(chuàng)建的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 (
<div style={{ width: '100%', height: '100%' }}>
<Canvas style={{ width: '100%', height: '100%' }}>
<ambientLight intensity={0.5} />
<directionalLight position={[-2, 5, 2]} intensity={1} />
<mesh
scale={3}
rotation={[0, Math.PI / 2, 0]}
>
<OrbitControls />
<Suspense fallback={null}>
<Car />
</Suspense>
</mesh>
</Canvas>
</div>
);
};
export default ThreeTest;