最近几个月一直在做自己的毕业设计, 仿照猫眼完成一整套的电影订票系统, 整个系统由 React 网页端, ReactNative 的手机端, Node 的服务端和管理系统组成. 虽然是完成了, 但是因为自己还在忙着实习的工作, 所以有些地方做得很粗糙. 这几天空闲下来打算把自己的代码整理一下, 梳理一下知识结构同时也想和更多人交流技术. 这里把我的代码里面的电影选座组件给独立出来, 并讲解一下实现的过程, 附上我的毕业设计的连接 https://github.com/xikou1314/movieTickets 和源码连接 https://github.com/xikou1314/choose-seat .
组件分析
猫眼官网上的电影选座组件截图如下:
原图
为了讲解的方便, 我对图中的一些部分进行了标号. 具体分析如下:
一., 座位分析
从 "1" 中可以看到, 整个组件中有 4 种类型的座位, 分别是可选, 已售, 已选, 情侣座位, 所有类型的座位都会在 "5" 的座位显示区域出现. 这个时候就需要思考怎么去保存座位的信息, 其中有几点需要注意:
1, 如何表示座位. 每个影厅的座位数不一样, 座椅的行数和列数都不相同. 甚至为了表示方便, 会出现 "座位空隙", 举个例子在某个影厅里面有一排楼梯, 这个楼梯的位置就要从影厅的布局上给预留出来.
2, 如何表示座位的状态. 一个座位从图中可以看到有 "可选","已售","已选" 的状态 (说明: 本次不考虑情侣座的情况), 需要采用一个恰当的方式, 去保存座位的状态.
二, 布局分析
. 左边是座位的选择区域, 左边上部是一些提示信息, 主体 "2" 是展示给用户看的主体部分, 所有的数据都是从后台获取. 且 "2" 的布局需要考虑到当行数过多时数据溢出的问题, 故需要在其超出显示范围时添加横向滚动跳条.
. 右边区域是有关电影和当前场次的一些基本信息, 其中 "座位" 这一栏需要与左边的座位选择区域发生联动关系. 是通过一些简单的使事件完成的, 这里也就没什么好讲的了.
三, 实现过程
1,create-react-app 安装
npm install create-react-app -g
具体请参照这个连接: https://segmentfault.com/a/1190000010454922
2, 创建项目
creact-react-app choose-seat
3, 配置路由
npm install react-router --save
在 src 目录下创建 router 文件夹
/src/router/index.js
路由
将创建好的路由注册到路由器中, 并挂载在根节点上:
/src/index.js
注册路由
4, 添加 MockJS 库
为了开发的方便, 采用 mock 模拟后台数据, 真实使用的时候需要将 Mock 拦截的请求去掉.
npm install mockjs --save-dev
在 src 目录下创建 mock 文件夹并新建 index.js
- src/mock/index.js
- Mock.setup({timeout: '100-300'});
- // 影厅座位信息
- Mock.mock('/roomInfo',{
- data: [
- [0,0,0,0,0,2,1,1,1,1,1,1,0,0,0,1,0,1,1],
- [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
- [1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,2,0,0,0],
- [1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,0,2,0,0],
- [1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0]
- ]
- });
- // 电影信息
- Mock.mock('/filmInfo',{
- data:{
- filmId:1,
- name: "复仇者联盟 3: 无限战争",
- type: "动作, 冒险, 科幻",
- duration: "150 分钟",
- cinema: "万达影院",
- filmRoom: "2 号影厅",
- version: "英语 3D",
- arrange: "今天 5 月 22 20:00",
- price: "32.5",
- poster: "../../assets/img/1.jpg"
- }
- })
5, 创建座位组件
如图所示, 作将 index.CSS 与 index.js 存放到一起, 方便到其他项目中进行复用.
组件图
电影座位的实现:
从前文中的 mock/index.js 中可以看到影厅的座位信息是以二进制数组进行表示的
- data: [
- [0,0,0,0,0,2,1,1,1,1,1,1,0,0,0,1,0,1,1],
- [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
- [1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,2,0,0,0],
- [1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,0,2,0,0],
- [1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0]
- ]
外层数组的长度表示行数, 内存数组的长度表示数组的列数, 0 表示这个位置没有座位, 1 表示 "可选座位",2 表示 "已售座位".
在编排座位的时候的难点主要是一个座位编码的问题, 比如第一排有 19 列却只有 10 个座位, 就要对其进行一次的编号 "1 排 1 座","1 排 2 座"....... 一直到 "一排 10 座", 需要将空位置跳过; 并且第二个数组全部都是空格, 所以就又涉及到排的跳过. 让第三个数组从 "2 排 1 座" 开始进行编号. 我是通过计算数组总和来进行判断的, 当然也有更好的方式:
- getSum(arr){
- return arr.reduce(function(prev, curr, index, arr){
- return prev + curr;
- });
- }
- click(row,column){
- let { roomInfo, seatCode, selectSeat } = this.state;
- if(roomInfo[row][column]===0 || roomInfo[row][column]===2)
- {
- return ;
- }
- let tmpRoom = _.cloneDeep(roomInfo);
- let tmpSeat = _.cloneDeep(selectSeat);
- if(tmpRoom[row][column] === 1 && tmpSeat.length<5) {
- tmpRoom[row][column] = 3;
- let code = _.cloneDeep(seatCode[row][column]);
- tmpSeat.push(code);
- } else if(tmpRoom[row][column] === 3) {
- tmpRoom[row][column] = 1;
- let index = _.findIndex(selectSeat,{row,column});
- tmpSeat.splice(index,1);
- }
- this.setState({
- roomInfo: tmpRoom,
- selectSeat: tmpSeat
- });
- }
而电影信息从另一个接口中可以拿到数据:
- data:{
- filmId:1,
- name: "复仇者联盟 3: 无限战争",
- type: "动作, 冒险, 科幻",
- duration: "150 分钟",
- cinema: "万达影院",
- filmRoom: "2 号影厅",
- version: "英语 3D",
- arrange: "今天 5 月 22 20:00",
- price: "32.5",
- poster: "../../assets/img/1.jpg"
- }
获得信息后直接展示到界面中来就可以了, 代码太多了, 我就不贴了. 可以再源码里面看到我的具体实现过程.
最后
感谢你能读到这里, 这是我第一次正式的写博文, 语言组织的不好, 希望得到你的谅解. 若有什么问题想问我的, 我看到以后会马上回复.
来源: http://www.jianshu.com/p/9e4efae8b617