在react中用canvas做一个电影院选座功能
2019-10-08 本文已影响0人
终身成长人格
又到了每日分享了。这次分享的是:在react中用canvas做一个电影院选座功能。
前言:项目采用create-react-app脚手架,就是做了一个效果所以只有一个页面但是也用了react-router-dom路由把details作为path=’/'首页了。

一、App.js
import React from 'react';
import {BrowserRouter,Route} from 'react-router-dom'
import Details from './routes/Details'
function App() {
return (
<div className="App">
<BrowserRouter>
<Route path='/' component={Details}></Route>
</BrowserRouter>
</div>
);
}
export default App;
这是入口文件的代码内容
二、Details.jsx
import React,{Component} from 'react';
import './Details.css';
import Footer from './Footer';
import SeatSelector from './SeatSelector'
class Details extends Component {
state = {
selectSeat:[]
}
addSeat = (seat)=>{
this.setState(prevState=>({
selectSeat:[...prevState.selectSeat,seat]
}))
}
removeSeat = (id)=>{
this.setState({
selectSeat:this.state.selectSeat.filter(seat=>seat.id !== id)
})
}
render() {
const {selectSeat} = this.state;
return (
<div>
<header>
<div className='header-container'>
<h2>决战时刻</h2>
<h3>今天 09-21 15:40~18:00 (国语 2D)</h3>
</div>
</header>
<div className='seat'>
<SeatSelector selected={selectSeat} onAdd={this.addSeat} onRemove={this.removeSeat}/>
</div>
<Footer data={selectSeat} onRemove={this.removeSeat}/>
</div>
);
}
}
export default Details;
这是效果的首页的东西了,分为3个部分(头部,中间canvas部分,底部),头部基本随便写,底部有一个选座显示几排几座的效果,主要是中间部分
三、SeatSelector.jsx
import React,{Component} from 'react';
import {data} from './mock/data.json';
const SET_WIDTH = 50;
const SET_HEIGHT = 50;
const lastSeat = data[data.length-1];
const canvas_width = lastSeat.x*SET_WIDTH;
const canvas_height = lastSeat.y*SET_HEIGHT;
class Details extends Component {
componentDidMount(){
this.ctx = this.refs.canvas.getContext('2d');
const emptyImg = new Image();
const selectImg = new Image();
const soldImg = new Image();
let count = 0;
const loadCallback = ()=>{
count++;
if(count===3){
this.emptyImg = emptyImg;
this.selectImg = selectImg;
this.soldImg = soldImg;
this.drawSeat();
}
}
emptyImg.onload = loadCallback;
selectImg.onload = loadCallback;
soldImg.onload = loadCallback;
emptyImg.src = './empty.png';
selectImg.src = './select.jpg';
soldImg.src = './sold.jpg';
}
componentDidUpdate(){
this.ctx.clearRect(0,0,canvas_width,canvas_height)
this.drawSeat();
this.drawSelectSeat();
}
drawSeat(){
const seatData = data;
seatData.forEach((item,index)=>{
const {isSold,x,y} = item;
const offsetLeft = (x-1)*SET_WIDTH;
const offsetTop = (y-1)*SET_WIDTH;
if(isSold){
this.ctx.drawImage(this.soldImg,offsetLeft,offsetTop,SET_WIDTH,SET_HEIGHT);
}else{
this.ctx.drawImage(this.emptyImg,offsetLeft,offsetTop,SET_WIDTH,SET_HEIGHT);
}
})
}
drawSelectSeat = ()=>{
const {selected} = this.props;
selected.forEach((item,index)=>{
const {isSold,x,y} = item;
const offsetLeft = (x-1)*SET_WIDTH;
const offsetTop = (y-1)*SET_WIDTH;
this.ctx.drawImage(this.selectImg,offsetLeft,offsetTop,SET_WIDTH,SET_HEIGHT);
})
}
clickSeat = (e)=>{
let offset = this.refs.canvas.getBoundingClientRect()
let pageX = e.pageX - offset.left;
let pageY = e.pageY - offset.top;
let xPos = Math.ceil(pageX/SET_WIDTH);
let yPos = Math.ceil(pageY/SET_HEIGHT);
let seat = data.find(seat=>seat.x===xPos && seat.y===yPos);
if( seat.isSold ){
return ;
}
const selectIndex = this.props.selected.findIndex(item=>item.id === seat.id);
if(selectIndex>-1){
this.props.onRemove(seat.id);
}else{
if(this.props.selected.length >= 6){
alert("不能超过6个");
}else{
this.props.onAdd(seat);
}
}
}
render() {
return (
<div>
<canvas onClick={this.clickSeat} ref='canvas' width={canvas_width} height={canvas_height}/>
</div>
);
}
}
export default Details;
这是中间canvas比较重要的一块了,大家可以看看代码了
四、Footer.jsx
import React from 'react';
import './footer.css';
const Footer = ({data,onRemove}) => {
return (
<footer>
<div className='seatNum'>
<ul>
{
data.map(seat=>(
<li key={seat.id} onClick={()=>onRemove(seat.id)}>
<p>{seat.y}排{seat.x}座</p>
<p>42.7元</p>
</li>
))
}
</ul>
</div>
<div className='seatSelect'>请先选座</div>
</footer>
)
}
export default Footer;
这是底部代码
老规矩附带视频教程:https://www.3mooc.com/front/couinfo/989