文章目录
前言
共同效果:前端获取后台位置信息,实现物体移动。
原本的效果(按钮)
(如效果图1)通过按钮实现:点击一次鼠标,物体改变一次位置。
更改效果(无按钮)
(如效果图2)物体实时获取后台信息,自动更换移动位置。
效果图1
效果图2
一、按钮实现物体移动?
1. 代码拆解
思路:通过索引index获取data数据对象,鼠标按钮控制index增加,进而获取下一位物体的位置信息。
2. 完整代码
import React, { Component } from 'react';
import styled from "styled-components";
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { Suspense } from "react";
// 3d模型导入
···
const Button = styled.button`
(按钮的css)
`;
let url = "后台接口url"
let start, goods;
const period = 4 // 数据周期为4
export default class All extends Component {
//react中的三大组件之一:state
state = {
index: 0, //索引
datas: [] //数据集
}
//生命周期function:将后台获取的数据存入state中
componentDidMount() {
//fetch默认式get请求,所以请求头设置部分可以省略
fetch(url)
.then(res => res.json())// 不是用户需要的数据,通过return返回给浏览器
.then(data => {// 服务器返回给客户端的数据
// console.log(data)
//把数据赋值给 datas 然后渲染在页面上
this.setState({
datas: data
})
//console.log(data)
})
}
//按钮点击函数
change = () => {
//遍历完成后,将state中的index=0重新遍历
if (goods.length !==0) {//goods获取一个对象数组,当数组为零,就修改state的index重新遍历
this.setState({
index: this.state.index + 1
})
} else {
this.setState({
index: this.state.index=0
})
}
//再次渲染,修改物体位置
this.render()
}
render() {
// console.log("index=", this.state.index)
let { index, datas } = this.state
// 获取本次交互物品数据
start = period * index //index=0
goods = datas.slice(start, start + period) // [0, 4) [4, 8)
console.log(goods)
return (
<>
<div>
<Button onClick={this.change}>变换位置</Button>
</div>
<Canvas>
{/* 3d模型放置 */}
<Suspense fallback={null}>
<Table position={[0, 0, 0]} />
{goods.map((item, index) => {
var x=item.x-100;
var y=item.y;
//角度转弧度
var angle = (item.Angle * Math.PI / 180)
// console.log(angle)
return (
<mesh key={index} position={[x, y, 2]} rotation={[angle,0,Math.PI]}>
{this.switchGoods(item.Name)}
</mesh>
);
})}
<OrbitControls />
</Suspense>
</Canvas>
</>
);
}
switchGoods = (type) => {
switch (type) {
case 'cup':
return (<Cup />)
case 'projector':
return (<Projector />)
case 'trash':
return (<TrashCan />)
case 'mecanum':
return (<Mecanum />)
default:
break;
}
}
}
二、无按钮实现实时移动
1.代码拆解
思路:通过定时执行,替换鼠标点击事件。
重点代码:定时执行(iTimer函数需要在render中调用)
iTimer = (goods) => {
console.log(goods)
this.timer = setTimeout(async () => {
//遍历完成后,将state中的index=0重新遍历
if (goods.length !==0) {
this.setState({
index: this.state.index + 1
})
} else {
this.setState({
index: 0
})
}
}, 100)
}
2. 完整代码
import React, { Component } from 'react';
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { Suspense } from "react";
// 3d模型导入
、、、
let url = "、、、"
let start, goods;
const period = 1 // 数据周期为1,逐个获取
export default class All extends Component {
state = {
index: 0,
datas: []
}
componentDidMount() {//生命周期function
//fetch默认式get请求,所以请求头设置部分可以省略
fetch(url)
.then(res => res.json())// 不是用户需要的数据,通过return返回给浏览器
.then(data => {// 服务器返回给客户端的数据
// console.log(data)
//把数据赋值给 datas 然后渲染在页面上
this.setState({
datas: data
})
console.log(data)
})
}
//定时执行(关键代码)
iTimer = (goods) => {
console.log(goods)
this.timer = setTimeout(async () => {
//遍历完成后,将state中的index=0重新遍历
if (goods.length !==0) {
this.setState({
index: this.state.index + 1
})
} else {
this.setState({
index: 0
})
}
}, 100)
}
render() {
//console.log("index=", this.state.index)
let { index, datas } = this.state
// 获取本次交互物品数据
start = period * index //index=0
goods = datas.slice(start, start + period) // 每次只取一个物品位置
//定时执行
this.iTimer(goods)
return (
<>
<Canvas>
{/* 3d模型放置 */}
<Suspense fallback={null}>
<Table position={[0, 0, 0]} />
//map循环遍历
{goods.map((item, index) => {
var x = item.x - 100;
var y = item.y;
//角度转弧度
var angle = (item.Angle * Math.PI / 180)
// console.log(angle)
return (
<mesh key={index} position={[x, y, 2]} rotation={[angle, 0, Math.PI]}>
{this.switchGoods(item.Name)}
</mesh>
);
})}
<OrbitControls />
</Suspense>
</Canvas>
</>
);
}
//按照物体名称,渲染3d物体
switchGoods = (type) => {
switch (type) {
case 'cup':
return (<Cup />)
case 'projector':
return (<Projector />)
case 'trash':
return (<TrashCan />)
case 'mecanum':
return (<Mecanum />)
default:
break;
}
}
}
3. 遇到的问题集
3.1 setInterval()越来越快的问题
- setInterval()
setInterval()方法可按照指定的周期来调用函数或者计算表达式(以毫秒为单位)
语法:
setInterval(函数表达式,毫秒数);
setInterval()会不停的调用函数,直到clearInterval()被调用或者窗口被关闭,由
setInterval()返回的ID值可用作clearInterval()方法的参数。
- setTimeout
setTimeout()方法用于在指定毫秒数后再调用函数或者计算表达式(以毫秒为单位)
语法:
setTimeout(函数表达式,毫秒数);
setTimeout()只执行函数一次,如果需要多次调用可以使用setInterval(),或者在函数体内再次调用setTimeout()
- 区别
- setTimeout()方法只运行一次,也就是说当达到设定的时间后就出发运行指定的代码,运行完后就结束了,如果还想再次执行同样的函数,可以在函数体内再次调用setTimeout(),可以达到循环调用的效果。
- setInterval()是循环执行的,即每达到指定的时间间隔就执行相应的函数或者表达式,是真正的定时器。
总结
react是个框架,react fiber是一种协调器。Fiber 协调器的主要目标是增量渲染,更好更平滑地渲染 UI 动画和手势,以及用户互动的响应性。
所以,react又或者是react fiber中遇到的逻辑问题、语法问题等,通通都可以转化为底层JavaScript问题进行思考。