【React】做一个百万答题小项目
- 因为这个小项目是按照开源项目实现的,所以只了解React和Redux实现方式就好,相关的引入框架和后台数据库相关暂时先不解释。(主要是没时间了,肝deadline。。。)
文章目录
- 1.安装框架和依赖
- 2.数据库配置
- 3.express实现数据获取
- 4.Store配置
- ajax数据请求
- Redux的state操作函数设置
- Redux的state设置
- Redux的store相关操作(state初始化 reducer创建)
- 5.store(state和函数)到props的映射
1.安装框架和依赖
用的是蚂蚁ant框架
npm install antd-mobile --save
然后导入样式
import { Button } from 'antd-mobile';
import 'antd-mobile/dist/antd-mobile.css';
还要安装插件
npm install babel-plugin-import --save
相关配置
npm run eject
package.json
"babel": {"presets": ["react-app"],"plugins": [["import", { "libraryName": "antd-mobile", "style": "css" }]]}
项目数据
- 数据导入:
Quizzes.json文件导入数据库。首先创建数据库,右键点击表,选择导入文件,文件导入json文件,后面一键跳过就行,最后一步点击完成。 - 创建服务器:
npm init
cnpm install express --save
cnpm install mysql --save
创建index.js文件
- 前端依赖
需要安装的内容:axios,react-router-dom,redux,react-redux,
相关目录树
2.数据库配置
- sql.js
设置连接,新建连接对象,let con = mysql.createConnection(connection);
并定义promise对象查询的方法,返回为promise对象。
const mysql = require('mysql');//配置连接
//这个自己设置哈
const connection = {host: 'localhost',post: '3306',user: 'root',password: 'root',database: 'timu'
};//创建连接对象
//let con = mysql.createConnection(connection);//连接
// con.connect(err => {// if (err) {// console.log('数据库连接失败');
// } else {// console.log('数据库连接成功');
// }
// });//创建promise对象查询方法function queryFn(sqlStr, arr) {//创建连接对象let con = mysql.createConnection(connection);return new Promise((resolve, reject) => {//找到了就返回并断开连接,没找到就拒绝连接con.query(sqlStr, arr, (error, result) => {if (error) {reject(error);} else {resolve(result);con.end()}});});
}module.exports = queryFn;
3.express实现数据获取
- 通过express()前端页面的路由监听进行对应后端数据库端口的数据获取
- 创建express对象并绑定前端页面端口,为了传输数据
- 端口监听事件绑定过后就要进行页面URL的路由绑定,比如对这个路由
'/api/rtimu/'
进行数据的获取 - 这里通过异步请求进行获取,因为获取时是跨域的页面是“8080”端口但是服务器端是“3306”所以要进行跨域请求设置
res.append("Access-Control-Allow-Origin","*") res.append("Access-Control-Allow-Content-Type","*")
- 通过sql语句进行数据库操作,这里sqlQuery的promise对象建立时就已经连接上数据库啦
- 然后数据转成json就可以给前端的store用啦
网页服务端的index.js
var express = require('express')
var app = express()
var sqlQuery = require('./sql')app.get('/',(req,res)=>{res.send("这是答题API服务器")
})//如果要获取第几页的数据 就 /:page
app.get('/api/rtimu/',async (req,res)=>{//随机获取10个题目;//console.log(req.query)//跨域请求res.append("Access-Control-Allow-Origin","*")res.append("Access-Control-Allow-Content-Type","*")//判断存不存在 存在就是page不存在就默认设为2let page = req.query.page?req.query.page:2;let strSql = `select * from quizzes limit ${page*10},10`;//这里要用到异步let result = await sqlQuery(strSql)//console.log(result)//Array.from(result)从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例res.json(Array.from(result));})//后端监听事件
//有关app.listen的解释
/*
app.listen = function listen() {var server = http.createServer(this);return server.listen.apply(server, arguments);
};
//this就是下面
var app = function(req,res,next){}
*/
app.listen(8080,()=>{console.log("server Start","http://localhost:8080/")
})
4.Store配置
ajax数据请求
- store/asyncMethods.js
- 通过随机生成page的值进行随机获取值
import axios from 'axios';
const host = 'http://localhost:8080'
let fns = {async TmList(){let page = parseInt(Math.random()*1600);let httpUrl = `${host}/api/rtimu/?page=${page}`let res = await axios.get(httpUrl);return res.data//console.log(res.dat)}
}export default fns;
Redux的state操作函数设置
- method.js
- 目的是为了在此对store中的state进行修改,也就是后面要调用到的dispatch
let methods = {add:function(state,action){state.num++return state},addNum:function(state,action){state.num = state.num + action.num;return state},setTimu:function(state,action){state.timuList = action.content;return state;}
}export default methods
Redux的state设置
let state = {timuList:[],
}export default state
Redux的store相关操作(state初始化 reducer创建)
import {createStore} from 'redux';
import methods from './methods';
import state from './state';let data = state;
//初始化state
//创建出reducer函数
let ActionFnObj=methods;
function reducer(state=data,action){if(action.type.indexOf('redux')===-1){state = ActionFnObj[action.type](state,action)return {...state}}else{return state;}
}const store = createStore(reducer)export default store
5.store(state和函数)到props的映射
- 建立映射函数(store.state和store.(dispatch函数))
- 然后通过connect方法进行组件类和store的绑定
我们通过这个思想来进行这个百万答题项目的页面渲染
- 首先是页面导航页面:App.js
- 通过映射获取state,但是本页面就直接跳转页面了,所以没有相关的store操作
import React from 'react';
import {connect} from 'react-redux'
import {Button} from 'antd-mobile'//将state映射到props函数
function mapStateToProps(state){return {...state}
}//将修改state数据的方法,映射到props,默认会传入store里的dispach方法
function mapDispatchToProps(dispatch){return {onAddClick:()=>{dispatch({type:'add'})},}
}class Counter extends React.Component{render(){return (<div><Button onClick={this.goDatiPage}>随机答题</Button><Button onClick={this.props.onAddClick5}>闯关答题</Button><Button onClick={this.props.onAddClick5}>抽奖答题</Button></div>)}goDatiPage=()=>{//console.log(this.props)this.props.history.push("/dati")}
}//将上面的这2个方法,将数据仓库的state和修改state的方法映射到组件上,形成新的组件。
const App = connect(mapStateToProps,mapDispatchToProps
)(Counter)export default App
- 然后是答题页面Dati.js
- 首先是state和state操作函数的props映射,这里通过传入dispatch的值进行store中的方法匹配
- 然后进行react的题目DOM页面渲染,题目就直接从state获取就行了
- 然后题目的选项上面要绑定一个判断正确与错误的事件,也是通过对state里面的数据进行获取匹配实现的
- 最后答完题还要进行一个页面push约等于刷新的事件,进行下一题的操作,这里有个小技巧就是通过对state的currentnum进行修改然后就能够重新唤起渲染事件进行页面刷新,并且如果>10还能跳转result界面。
import React from 'react';
import {connect} from 'react-redux'
// import {Button} from 'antd-mobile'
import fns from '../store/asyncMethods'
import loadingImg from '../assets/img/loading.gif' //将state映射到props函数
function mapStateToProps(state){return {...state}
}//将修改state数据的方法,映射到props,默认会传入store里的dispach方法
function mapDispatchToProps(dispatch){return {onAddClick:()=>{dispatch({type:'add'})},getTimu:async ()=>{let list = await fns.TmList()dispatch({type:"setTimu",content:list})console.log(list)}}
}class DatiCom extends React.Component{constructor(props){super(props)this.state = {currentTimu:0,optionsStyle:['optionItem','optionItem','optionItem','optionItem'],isChoose:false,score:0}}componentDidMount(){this.props.getTimu()}render(){console.log(this.props)console.log(this.state.currentTimu)let timuArr = this.props.timuList;let currentNum = this.state.currentTimu;let oStyle = this.state.optionsStyle;//如果数据没有加载进来,就设置为loadingif(timuArr.length>0){let options = JSON.parse(timuArr[currentNum].options) return (<div className="datiPage"><h2>{currentNum+1}-{timuArr[currentNum].quiz}</h2><div className="options">{options.map((item,index)=>{return (<div key={index} className={oStyle[index]} onClick={()=>this.answerEvent(index)}>{index+1}: {item}</div>)})}</div></div>)}else{return (<div><img alt="img" src={loadingImg} /></div>)}}goDatiPage=()=>{//console.log(this.props)this.props.history.push("/dati")}answerEvent=(index)=>{if(this.state.isChoose){return true;}console.log(index)let currentAnswer = this.props.timuList[this.state.currentTimu].answer;console.log(currentAnswer)let score = this.state.score;if((index+1)===Number(currentAnswer)){let optionsStyle = this.state.optionsStyle;optionsStyle[index] = "optionItem correct";this.setState({optionsStyle:optionsStyle,isChoose:true,score:score+10})}else{let optionsStyle = this.state.optionsStyle;optionsStyle[index] = "optionItem error";optionsStyle[(Number(currentAnswer)-1)] = "optionItem correct"this.setState({optionsStyle:optionsStyle,isChoose:true})}//2秒跳转至下一题setTimeout(() => {let currentNum = this.state.currentTimucurrentNum++if(currentNum===10){this.props.history.push('/result',{score:this.state.score})}else{this.setState({currentTimu:currentNum,optionsStyle:['optionItem','optionItem','optionItem','optionItem'],isChoose:false})}}, 2000);}
}//将上面的这2个方法,将数据仓库的state和修改state的方法映射到组件上,形成新的组件。
const Dati = connect(mapStateToProps,mapDispatchToProps
)(DatiCom)export default Dati
- result.js
- 实现获取props的state数据进行分数统计
import React from 'react';
import {connect} from 'react-redux'
import {Button} from 'antd-mobile'//将state映射到props函数
function mapStateToProps(state){return {...state}
}//将修改state数据的方法,映射到props,默认会传入store里的dispach方法
function mapDispatchToProps(dispatch){return {onAddClick:()=>{dispatch({type:'add'})},}
}class Counter extends React.Component{render(){console.log(this.props)return (<div><h1>恭喜您获得{this.props.location.state.score}分</h1><Button onClick={this.goDatiPage}>回到首页</Button></div>)}goDatiPage=()=>{//console.log(this.props)this.props.history.push("/")}
}//将上面的这2个方法,将数据仓库的state和修改state的方法映射到组件上,形成新的组件。
const App = connect(mapStateToProps,mapDispatchToProps
)(Counter)export default App
- index.js 主渲染文件
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux'
import {BrowserRouter as Router,Route} from 'react-router-dom';
import store from './store/data'
import App from './view/App'import './assets/css/style.css'import Dati from './view/Dati'
import Result from './view/Result'
ReactDOM.render(<Provider store={store}><Router><Route path="/" exact component={App}></Route><Route path="/dati" component={Dati}></Route><Route path="/result" component={Result}></Route></Router></Provider>,document.querySelector("#root")
)
最后再来点css特效
/* .datiPage{} */
.datiPage h2{width: 90%;margin: 10px auto;
}
.options{width: 90%;display: flex;flex-direction: column;height: 400px;margin: 20px auto;border-radius: 10px;background-color: #efefef;justify-content: space-around;align-items: center;}.optionItem{width: 90%;height: 60px;line-height: 60px;padding: 0 10px;background-color: lightblue;border-radius: 10px;
}.optionItem.correct{background-color: lightgreen;color: #fff;
}.optionItem.error{background-color: orangered;color: #fff;
}
谢谢阅读,over!
【React】做一个百万答题小项目相关推荐
- 零基础做一个微信答题小程序(四)
嗨!大家好,我是小蚂蚁.这一节里,我们继续分享如何在答完题后进行答案的比对,以及如何实现一个回顾功能. 在上一节里我们提到过,为了记录玩家的答题数据,我们创建了一个新的表格--玩家答题选项表,里面记录 ...
- 零基础做一个微信答题小程序(二)
嗨!大家好,我是小蚂蚁.在上一节里,我们了解了如何设计答题小程序中的题库--表格,并且知道了如何从题库中随机抽取指定数量的不重复的题目编号.这一节,我们将分享一下如何利用这些题目编号,获取到指定的题目 ...
- 零基础做一个微信答题小程序(三)
嗨!大家好,我是小蚂蚁.今天我们来分享一下如何实现答题功能,包含单选题和多选题的答题,以及如何记录玩家的答题数据. 单选题答题处理 对于单选题来讲,每个选项之间是互斥的,也就是说用户只能从 ABCD ...
- 跟我一起做一个vue的小项目(十一)
接下来我们进行的是详情页动态路由及banner布局 先看页面的效果 下面是代码部分 <template><div><div class="banner" ...
- 跟我一起做一个vue的小项目(九)
接下来我们进行的就是城市列表页面数据额动态渲染. 也是在mock数据,进行动态渲染 //city.json {"ret": true,"data":{" ...
- 从0到1使用python开发一个半自动答题小程序
从0到1使用python开发一个半自动答题小程序 前言 最近每天都有玩微信读书上面的每日一答的答题游戏,完全答对12题后,可以瓜分无限阅读卡.但是从小就不太爱看书的我,很难连续答对12道题,由此,产生 ...
- 0301 - 一个比价的小项目
这两天帮朋友做了个 比价 的小项目,主要是为了练手 Vue 及相关网站开发. 主要功能: 批量查询产品对应的京东价格 手动根据京东价格调整批发价格 将产品及价格信息,以网页形式分享出去 由于是私人项目 ...
- 如何做一个优秀的数据分析项目?
上一篇我们普及了[数据分析项目,是什么?为什么我没做过?].今天我们系统讲解一下:如何做一个优秀的数据分析项目.首先大家要明白,并不是所有的项目,都需要找一个万人大会堂,拉着横幅,董事长总经理轮流上台 ...
- 用 typescript 做一个贪吃蛇小游戏
typescript 做一个贪吃蛇小游戏 搭建环境 创建 tscofig.json 文件 配置如下 {"compilerOptions": {"target": ...
最新文章
- 2021年大数据Kafka(八):Kafka如何保证数据不丢失
- 使用Java方法实现 Double和String相互转化
- 一个 .Net Hashtable 的锁的疑惑和解决
- 路由 交换 网桥 相关转贴
- javame学习_从零基础自学Java教程:648集全网最新Java学习教程,一学就会
- centos7手把手教你搭建zabbix监控
- 如何获取select中的value、text、index相关值 如何获取单选框中radio值 触发事件 radio 默认选中...
- DelphiARX 2000i 简介
- android 系统宏定义,Android.mk宏定义demo【转】
- JavaScript学习第一天——计算机基础导学(编程语言、计算机基础)
- 电大在线计算机考试,2016电大计算机考试题库(计算机应用基础选择题)
- 中国最顶级的一批程序员,从首富到首负!
- win教程:如何查看本机的IP地址
- chrome禁止广告
- Keras中那些学习率衰减策略
- 论巴西世界杯带给移动互联网产品的契机!
- 2022.4月份科研记录【日记】
- eclipes的安装与使用
- java 实例化异常_如何处理实例化类对象时发生的异常
- DEAP2.1——数据包络分析(DEA——CCR、BCC)