项目实战-选座购票
【例14.7】实现选座购票的功能。(实例位置:资源包\源码\14\07)
本节将使用 express-generator
框架模拟实现电影院选座购票的效果,如图 14.21 所示。

下面讲解该案例的具体实现过程。
服务器实现
(1) 在 WebStorm 中创建一个 app.js
文件,在该文件中,首先导入相关模块,然后定义 seats
变量,以使用数组来存储座位,其中,1 表示未售出的座位,0 表示不是座位,2 表示已售出的座位。app.js
文件中的代码如下:
//导入模块
var socketio = require('socket.io');
var express = require('express');
var http = require('http');
var fs = require('fs');
//声明变量
var seats = [
[1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
];
(2) 创建 Web
服务器,并使用 app.get()
设置 GET
请求的页面路由跳转规则,然后使用 static
中间件设置资源导入位置,代码如下:
//创建Web服务器
var app = express();
var server = http.createServer(app);
//创建路由
app.get('/', function (request, response, next) {
fs.readFile('HTMLPage.html', function (error, data) {
response.send(data.toString());
});
});
app.use(express.static('./'));
app.get('/seats', function (request, response, next) {
response.send(seats);
});
(3) 启动服务器,并且创建 WebSocket
服务器,监听到有客户端连接服务器时,接收自定义的 reserve
事件,该事件中将指定座位设置为已售出状态,并将相应数据回传给客户端。代码如下:
//启动服务器
server.listen(52273, function () {
console.log('Server Running at http://127.0.0.1:52273');
});
//创建WebSocket服务器
var io = socketio(server);
//监听连接事件
io.sockets.on('connection', function (socket) {
socket.on('reserve', function (data) {
seats[data.y][data.x] = 2;
//向所有客户发送座位消息
io.sockets.emit('reserve', data);
});
});
客户端实现
(1) 创建 HTMLPage.html
文件,作为客户端页面,在该页面中添加电影名称和日期,并设置页面样式,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>选座购票</title>
<style>
.line { overflow: hidden; }
.seat { margin: 2px; float: left; width: 40px; height: 35px; }
.seat img{
width: 40px; height: 35px;
}
</style>
<script src="js/jQuery-v3.4.0.js"></script>
<script src="/socket.io/socket.io.js"></script>
</head>
<body>
<h1>惊奇队长</h1>
<p>今天3月14日 16:00 英语3D</p>
</body>
</html>
(2) 使用 io.connect()
方法向服务器端发起连接请求,然后监听服务器端发送的 reserve
事件,获取服务器端传送的座位信息,修改接收到的指定座位对应的 div
类名以及 data-x
和 data-y
属性值,并更改指定座位的状态显示。代码如下:
<script>
//向服务器端发送连接请求
var socket = io.connect();
//监听reserve事件
socket.on('reserve', function (data) {
var $target = $('div[data-x = ' + data.x + '][data-y = ' + data.y + ']');
$target.removeClass('enable');
$target.addClass('disable');
});
</script>
(3) 通过遍历服务器端传回的数据生成要显示的座位,显示在相应的标签中,并根据显示状态确定是否为其添加单击事件;然后在用户单击座位时,记录单击的座位坐标,并判断是否单击了弹出框中的 “确定” 按钮,如果是,向服务器端发送用户选中的座位坐标,同时移除该座位的单击事件。代码如下:
<script>
//是否选择座位
$(document).ready(function () {
var onClickSeat = function () {
var x = $(this).attr('data-x');
var y = $(this).attr('data-y');
if (confirm('确定吗?')) {
$(this).off('click');
socket.emit('reserve', {
x: x,
y: y
});
} else {
alert('已取消!');
}
};
//执行Ajax
$.getJSON('/seats', { dummy: new Date().getTime() }, function (data) {
//生成座位
$.each(data, function (indexY, line) {
//生成HTML
var $line = $('<div></div>').addClass('line');
$.each(line, function (indexX, seat) {
var $output1 = $('<div></div>', {
'class': 'seat',
'data-x': indexX,
'data-y': indexY
}).appendTo($line);
var $output=$("<img src='image/yes.png' alt=''>")
if (seat == 1) {
$output1.addClass('enable').on('click', onClickSeat);
$output.appendTo($output1)
} else if (seat == 2) {
$output1.addClass('disable');
$output.appendTo($output1)
$output.attr("src","image/no.png")
}
});
$line.appendTo('body');
});
});
});
</script>
运行项目
运行 app.js
服务器端文件,打开浏览器,输入地址 http://127.0.0.1:52273 ,页面初始效果如图 14.22 所示。

当有用户选择座位后,刷新当前页面,可以看到座位信息的变化,如图 14.23 所示。
