100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 抽奖大转盘-React-移动端

抽奖大转盘-React-移动端

时间:2022-03-06 11:13:47

相关推荐

抽奖大转盘-React-移动端

抽奖大转盘-React-移动端

react安装修改项目结构配置路由删除一些不必要的文件大转盘整理代码结构和一些静态资源书写静态页面移动端px-rem转换静态页面静态页面样式抽奖大转盘思路分析伪代码代码实现整体js代码

react安装

链接: react安装.

操作流程(可跟着操作一步一步走)

1.在我的电脑里随便打开一个硬盘(我这里是D盘)

2.鼠标右键选中Git Bash Here会打开一个小黑框(如下图)

3.最后依次输入

npm install -g create-react-app

create-react-app my-app

cd my-app/

npm start(最好把构建的my-app项目拖入到VS code编辑器里运行的,操作如下)

打开 vs code 编辑器,依次按下Ctrl + kCtrl + o,然后选中刚刚创建的项目文件,打开然后打开新终端(Ctrl + Shift + `)在终端中输入 npm start 运行项目npm install react-router-domnpm install sass-loader node-sass --save-dev

修改项目结构

配置路由

在项目src文件夹内创建一个新的文件夹(page),这里主要放一些单页面,如图在上图index.js文件中构建route(路由)
首先安装react-router-dom, 命令:npm install react-router-dom安装scss相关配置(本文是基于create-react-app的,会根据该版本来进行scss相关的配置,所以我们可以直接安装) 命令:npm install sass-loader node-sass --save-dev然后重新安装一下依赖npm install再启动npm start
注:这里我出现了 安装不成功的 操作,最后用的yarn命令成功了操作: 先安装yarn, 命令:npm install -g yarnyran add sass-loader node-sass --save-dev这样操作后成功安装了scss
引入相关文件

import React from 'react';import ReactDOM from 'react-dom';import {Redirect, HashRouter, Route } from 'react-router-dom'; // 引入路由import './index.scss'; // 引入公共样式import Home from './page/home/index.js';import LuckDraw from './page/luckDraw/index.js';/*** 根据路由渲染页面*/ReactDOM.render(<HashRouter><div>{/* 路由重定向到 /home页面 */}<Route exact path='/' component={() => <Redirect to="/home" />}></Route> <Route path='/' component={Home}></Route><Route path='/luckDraw' component={LuckDraw}></Route></div></HashRouter>,document.getElementById('root'));

删除一些不必要的文件

以上标注的文件都删除

大转盘

整理代码结构和一些静态资源

抽奖大转盘主要的三张图

这些图片放在img文件夹下,img文件夹在luckDraw文件夹内部

书写静态页面

移动端px-rem转换

Ctrl + A复制下面的代码放到public下的index.html

放到 ** index.html** 里也是整体粘贴

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><link rel="icon" href="%PUBLIC_URL%/favicon.ico" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="theme-color" content="#000000" /><metaname="description"content="Web site created using create-react-app"/><script>function adapt(e, t) {var n = window.document.createElement("div");return ((n.style.width = "1rem"),(n.style.display = "none"),window.document.getElementsByTagName("head")[0].appendChild(n),parseFloat(window.getComputedStyle(n, null).getPropertyValue("width")));}!(function (e, t, n, d) {var i = e.documentElement,o = adapt(750, 100),a = "orientationchange" in window ? "orientationchange" : "resize",r = function () {var n =t.innerWidth ||e.documentElement.clientWidth ||e.body.clientWidth;n && (i.style.fontSize = n < 750 ? (((n / 750) * 100) / o) * 100 + "%" : "625%");};e.addEventListener && (t.addEventListener(a, r, !1),e.addEventListener("DOMContentLoaded", r, !1));})(document, window);</script><script src="/g/component/fastclick/1.0.6/fastclick.js"></script><script>if ('addEventListener' in document) {document.addEventListener('DOMContentLoaded', function() {FastClick.attach(document.body);}, false);}if(!window.Promise) {document.writeln('<script src="/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>');}</script></head><body><div id="root"></div></body></html>

静态页面

import React from 'react';import './index.scss';import btn from './img/btn.png';export default class LuckDraw extends ponent {constructor(props) {super(props);this.state = {}}render() {return (<div className="luckDraw"><div className="box">{/* 底座 */}<div className="base"> {/* 转盘 */}<div className="turntable"></div>{/* 指针 */}<div className="btn"><img src={btn} alt="" /></div></div></div></div>)}}

静态页面样式

.luckDraw{width:100%;height:100%;overflow: hidden;.box {.base{width: 7.2rem;height: 8.7rem;box-sizing: border-box;background:url("./img/base.png") no-repeat center;background-size: 100% 100%;position: relative;padding: .6rem 0 0;margin: 0 auto;// 转盘样式.turntable{width: 5.15rem;height: 5.15rem;background-image: url(./img/turntable.png);background-size: 100% 100%;position: relative;box-sizing: border-box;margin: 0 auto .8rem;}// 按钮样式.btn{width: 1.4rem;height: 1.8rem;position: absolute;left: 50%;margin-top: -1.2rem;top: 50%;transform: translate(-50%, -50%);text-align: center;img{width: 100%;}}}}}

抽奖大转盘

思路分析

1.现实中的抽奖转盘是一个奖品展示圆盘,加一个指针

2.用户给转盘一个力度,让转盘转动,转盘先是加速转动,到达最大速度后慢慢减速,直至转盘停止转动,最后指针会指向转盘上的某一区域

伪代码

1.用户给转盘一个力度,这里我们在抽奖按钮上添加一个点击事件函数onClick={this.luckDraw}

2.转盘在刚开始的时候是停在某一位置的,我们这里给它固定一个角度this.degree = 0, 让他固定指针指向0° 。

3.转盘先加速,到最大速度后,然后再减速,我们这里给它一个固定的加速度this.a = 0.5,和减速度this.d = - 0.5,和转动的初始速度this.v = 0

4.转盘从开始转动,到停止转动之间,转盘是一直处于转动的状态,我这里的处理是,写一个动画循环,让转盘一直转。

5.用户在给转盘力度后,转盘会有一个加速度的过程,我们定义加速度的过程为1s,这样转盘会从初始速度为0,加速1s置加速度最大(这里是加速度最大,不是速度最大),然后加速度慢慢减小(这里速度还在增加,只是加速度减小),到最大速度后(转盘的最大速度),慢慢减速,直至停在中奖位置。

代码实现

1.添加点击事件(伪代码中第一条)

render() {const {rotate } = this.state;return (<div className="luckDraw"><div className="box">{/* 底座 */}<div className="base"> {/* 转盘 */}<div className="turntable" style={rotate}></div>{/* 指针 */}<div className="btn"><img src={btn} alt="" onClick={this.luckDraw} /></div></div></div></div>)}

2.定义初始参数和值,构建好动画循环函数,使转盘转动的函数一直执行

这里我们定义抽中的是第二个奖品,设置this.result = 2,后面可使用随机数抽取1~8号奖品(8个奖品是,转盘上有8个格子)(伪代码中第二到第四条)

luckDraw = () => {// this.result = Math.floor(Math.random()*(8-1+1)+1);// 随机1~8的整数this.result = 2;// 先定义一个默认抽中的奖品序号为 2this.isAnimation = true;// 动画循环的开关//动画参数this.degree = 0;// 初始角度 默认为0this.time = Date.now(); // 初始启动动画时间,记录下来this.a = 0.5; // 加速度this.d = -0.5; // 减速度this.v = 0; // 初始速度//动画循环let frame = () => {// 判断 isAnimation 为 false 的时候,停止动画if (!this.isAnimation) {return;}// window.requestAnimationFrame这个API是浏览器提供的js全局方法,针对动画效果,感兴趣的同学可以自行搜索学习window.requestAnimationFrame(frame);this.update();// 转盘执行帧逻辑的函数(转盘转动的逻辑函数)};frame();// 执行动画}

3.帧逻辑代码(重点解释)

1.前面说加速度增加时间为1s,这里生成一个转盘开始转动的时间,转动时间 - 初始时间,小于1s表示加速度还在增加中,反之为加速度开始减小2.判断转盘停止的条件-在减速的情况下,即加速度小于0,-速度要小于一定值3.处理转盘达到临界值的角度-先计算实际转盘停止后的角度: 总共转动的角度 / 360 他的余数就是实际停止后的角度-处理后的角度:先判断实际的角度和要转到的角度(下面统称定义角度)的大小解释:定义角度是上文说到的默认抽中的奖品序号*45°(因为8个奖品,360° / 8 = 45°)a: 如果实际角度大于定义角度定义总旋转度数 = (实际总度数/360°)向上取整后*360° + 抽中的奖品序号*45°b: 如果实际角度小于定义角度定义总旋转度数 = (实际总度数/360°)向下取整后*360° + 抽中的奖品序号*45°4.转动到定义的角度后,停止转动,结束动画循环。

// 帧逻辑 动画的最终目标是转了多圈之后定位到this.degree的角度update() {let now = Date.now(); // 转盘开始转动的时间let continueTime = now - this.time;let a = continueTime < 1000 ? this.a : this.d; // 判断是加速度还是减速度// 到达临界值转盘旋转的速度:旋转时的速度(this.v)小于的值 越大速度越快,时间越短if (this.v <= 10 && a < 0) {/*** 到达临界值转盘旋转的角度* 旋转时的速度(this.v)越大达到临界值时调整角度的速度就越大,* 数越小调整角度的速度小 (大于200后体现的不明显)*/this.v = 50;let nowDeg = this.degree % 360; // 到达临界值,实际停止角度// console.log(123, this.degree, nowDeg);// 实际的停止角度 大于 定义的停止角度if (nowDeg > this.result * 45) {// 定义的总度数 = (实际总度数/360°)向上取整后*360° + 抽中的奖品序号*45°this.finalDeg = Math.ceil(this.degree / 360) * 360 + this.result * 45;console.log("临界值1", this.a, this.v, this.finalDeg);} else {// 定义总旋转度数 = (实际总度数/360°)向下取整后*360° + 抽中的奖品序号*45°this.finalDeg = Math.floor(this.degree / 360) * 360 + this.result * 45;console.log("临界值2", this.v, this.finalDeg);}} else {// 未到达临界值,速度每次都加上加速度的值,让速度从开始加速到减速再到停止this.v += a;}// 总的角度 = 转盘的速度 * 1 (这里的1是一帧)this.degree += this.v;// console.log('度数', this.v, this.degree)// 实际总角度大于定义总角度 且 定义总角度不为零if (this.degree >= this.finalDeg && this.finalDeg !== 0) {console.log('this.degree, this.finalDeg', this.degree, this.finalDeg);// 把定义的总角度赋值给实际总角度this.degree = this.finalDeg;// 转盘停止后,停止抽奖动画this.isAnimation = false;// 转盘停止后的提示,传奖品序号this.prompt(this.result);}// 抽奖转盘旋转的角度 (样式)this.setState({rotate: this._rotateStyle(this.degree) });}// 转盘旋转的角度 (样式)_rotateStyle(deg) {return {WebkitTransform: `rotate3d(0,0,1,${deg}deg)` };}// 打印抽中的奖品序号prompt(number) {console.log('number', number);}

整体js代码

import React from 'react';import './index.scss';import btn from './img/btn.png';export default class LuckDraw extends ponent {constructor(props) {super(props);this.state = {}}luckDraw = () => {this.result = Math.floor(Math.random()*(8-1+1)+1); // 随机1~8的整数// this.result = 2; // 先定义一个默认抽中的奖品序号为 2this.isAnimation = true; // 动画循环的开关//动画参数this.degree = 0; // 初始角度 默认为0this.time = Date.now(); // 初始启动动画时间,记录下来this.a = 0.5; // 加速度this.d = -0.5; // 减速度this.v = 0;// 初始速度//动画循环let frame = () => {if (!this.isAnimation) {return;}// window.requestAnimationFrame这个API是浏览器提供的js全局方法,针对动画效果window.requestAnimationFrame(frame);this.update();};frame();}// 帧逻辑 动画的最终目标是转了多圈之后定位到this.degree的角度update() {let now = Date.now(); // 转盘开始转动的时间let continueTime = now - this.time;let a = continueTime < 1000 ? this.a : this.d; // 判断是加速度还是减速度// 到达临界值转盘旋转的速度:旋转时的速度(this.v)小于的值 越大速度越快,时间越短if (this.v <= 10 && a < 0) {/*** 到达临界值转盘旋转的角度* 旋转时的速度(this.v)越大达到临界值时调整角度的速度就越大,* 数越小调整角度的速度小 (大于200后体现的不明显)*/this.v = 50;let nowDeg = this.degree % 360; // 到达临界值,实际停止角度// console.log(123, this.degree, nowDeg);// 实际的停止角度 大于 定义的停止角度if (nowDeg > this.result * 45) {// 定义的总度数 = (实际总度数/360°)向上取整后*360° + 抽中的奖品序号*45°this.finalDeg = Math.ceil(this.degree / 360) * 360 + this.result * 45;console.log("临界值1", this.a, this.v, this.finalDeg);} else {// 定义总旋转度数 = (实际总度数/360°)向下取整后*360° + 抽中的奖品序号*45°this.finalDeg = Math.floor(this.degree / 360) * 360 + this.result * 45;console.log("临界值2", this.v, this.finalDeg);}} else {// 未到达临界值,速度每次都加上加速度的值,让速度从开始加速到减速再到停止this.v += a;}// 总的角度 = 转盘的速度 * 1 (这里的1是一帧)this.degree += this.v;// console.log('度数', this.v, this.degree)// 实际总角度大于定义总角度 且 定义总角度不为零if (this.degree >= this.finalDeg && this.finalDeg !== 0) {console.log('this.degree, this.finalDeg', this.degree, this.finalDeg);// 把定义的总角度赋值给实际总角度this.degree = this.finalDeg;// 转盘停止后,停止抽奖动画this.isAnimation = false;// 转盘停止后的提示,传奖品序号this.prompt(this.result);}// 抽奖转盘旋转的角度 (样式)this.setState({rotate: this._rotateStyle(this.degree) });}// 转盘旋转的角度 (样式)_rotateStyle(deg) {return {WebkitTransform: `rotate3d(0,0,1,${deg}deg)` };}// 打印抽中的奖品序号prompt(number) {console.log('number', number);}render() {const {rotate } = this.state;return (<div className="luckDraw"><div className="box">{/* 底座 */}<div className="base"> {/* 转盘 */}<div className="turntable" style={rotate}></div>{/* 指针 */}<div className="btn"><img src={btn} alt="" onClick={this.luckDraw} /></div></div></div></div>)}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。