在前面的系列文章中已经简单的实现了石头剪刀布这个小游戏,现在来把它改造成网页版,可以在这里学会通过解析 url
来获取对应的行为并返回相应的数据。
网页版改造
在这里先附上效果图:
HTML 代码比较简单,通过石头剪刀布的三个按钮操作和一个输出显示结果的画布来达到浏览器和计算机交互的一个效果,index.html
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>网页版石头剪刀布小游戏</title>
<style>
.btn {
color: #fff;
background-color: #409eff;
border-color: #409eff;
line-height: 1;
white-space: nowrap;
cursor: pointer;
border: 1px solid #dcdfe6;
font-weight: 500;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
width: 100px;
margin: 20px 20px 0;
}
.output {
background-color: #e6effb;
height: 600px;
width: 400px;
margin: 20px;
padding: 10px;
}
</style>
</head>
<body>
<button id="rock" class="btn">石头</button>
<button id="scissor" class="btn">剪刀</button>
<button id="paper" class="btn">布</button>
<div id="output" class="output"></div>
</body>
<script>
const $button = {
rock: document.getElementById('rock'),
scissor: document.getElementById('scissor'),
paper: document.getElementById('paper')
}
const $output = document.getElementById('output')
// 绑定事件
Object.keys($button).forEach(key => {
$button[key].addEventListener('click', function () {
fetch(`http://${location.host}/game?action=${key}`).then((res) => {
return res.text()
}).then((text) => {
$output.innerHTML += text + '<br/>';
})
})
})
</script>
</html>
石头剪刀布游戏模块 game.js
如下,把它分离出来成一个模块可以达到 复用 的效果。
// game.js
module.exports = function (playerAction) {
if (['rock', 'scissor', 'paper'].indexOf(playerAction) == -1) {
throw new Error('请输入rock或paper或scissor');
}
// 电脑通过随机数生成石头剪刀布
var computerAction;
var random = Math.random() * 3
if (random < 1) {
computerAction = 'rock'
} else if (random > 2) {
computerAction = 'scissor'
} else {
computerAction = 'paper'
}
// 比较分出输赢
if (computerAction === playerAction) {
return 0;
} else if (
(computerAction == 'rock' && playerAction == 'scissor') ||
(computerAction == 'scissor' && playerAction == 'paper') ||
(computerAction == 'paper' && playerAction == 'rock')
) {
return -1;
} else {
return 1;
}
}
HTTP 服务 index.js
,这里需要用到两个模块:
- 内置模块
url
,实现转换发送到该HTTP 服务上的 HTTP 请求包的url
- 内置模块
querystring
可以对 HTTP 请求所带的数据进行解析
// index.js
const http = require('http');
const fs = require('fs');
const url = require('url'); // 加载内置模块url,实现转换发送到该http服务上的http请求包的url
const querystring = require('querystring'); // 模块 querystring 可以对http请求所带的数据进行解析
const game = require('./game');
let playerWon = 0; // 赢的次数
http.createServer(function (request, response) {
// 将其分割成 协议(protocol)://域名(host):端口(port)/路径名(pathname)?请求参数(query)
const parsedUrl = url.parse(request.url);
// 浏览器所有对这个服务器的请求,都会走到这个http.createServer的回调函数里
// 所以这里对不同的请求url做判断,就可以处理不同url的请求的返回
// 如果请求url是浏览器icon,比如 http://localhost:3000/favicon.ico的情况
// 就返回一个200就好了
if (parsedUrl.pathname == '/favicon.ico') {
response.writeHead(200);
response.end();
return;
}
// 如果访问的是根路径,则把游戏页面读出来返回出去
if (parsedUrl.pathname == '/') {
fs.createReadStream(__dirname + '/index.html').pipe(response);
}
if (parsedUrl.pathname == '/game') {
// 如果请求url是游戏请求,比如 http://localhost:3000/game?action=rock的情况
// 就要把action解析出来,然后执行游戏逻辑
const query = querystring.parse(parsedUrl.query);
// 获取用户操作
const playerAction = query.action;
// 统计的玩家胜利次数超过3
if (playerWon >= 3) {
response.writeHead(500);
response.end('我再也不和你玩了!');
return
}
// 执行游戏逻辑,返回游戏结果
const gameRes = game(playerAction);
// 先返回头部
response.writeHead(200);
// 根据不同的游戏结果返回不同的说明
if (gameRes == 0) {
response.end('平局!');
} else if (gameRes == 1) {
response.end('你赢了!');
playerWon++; // 玩家胜利次数统计+1
} else {
response.end('你输了!');
}
}
}).listen(3000)
在终端运行命令:node index.js
,浏览器打开 http://localhost:3000/
即可。