【五子棋实战】第5章 开发五子棋前端页面

news/2024/10/25 14:30:00/

【五子棋实战】第5章 开发五子棋前端页面

  • 页面设计原则
  • 开发页面
    • ## 基础HTML骨架
    • ## 添加页面响应式功能
  • 编写JS
    • ## 获取画布对象与DOM对象
    • ## 定义棋子、棋盘对象
    • ## 定义绘画对象(重要!!)
    • ## 初始化绘制棋盘
    • ## 添加点击事件 能够下棋落子
  • 继续学习下一篇实战!

页面设计原则

  1、可配置性。比如棋盘的大小可配置,棋盘边长可配置,黑白空期的值可配置;
  2、响应式。各种屏幕大小下棋盘的布局要合理;
  3、面向对象。棋子、棋盘的定义都用类来封装,代码要写的好看。


开发页面

## 基础HTML骨架

  代码如下:

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>三黄工作室 - 五子棋</title><style>*{margin: 0;}body{background-image: url("img/bg.png");}#canvas_line {box-shadow: 0 0 5px 0px rgba(0, 0, 0, .8);border-radius: 5px;box-sizing: border-box;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);border: 1px solid black;background-color: #ffbd5b;z-index: 5;}#canvas_chess {position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 10;}.loading-message {/* background-color: #f5f5f5; */padding: 5px;text-align: center;font-size: 18px;font-weight: bold;color:white;}.logo{background-color: #FCFCFD;padding: 5px;text-align: center;bottom: 0px;position: fixed;width: 100%;}.button-30 {align-items: center;appearance: none;background-color: #FCFCFD;border-radius: 4px;border-width: 0;box-shadow: rgba(45, 35, 66, 0.4) 0 2px 4px,rgba(45, 35, 66, 0.3) 0 7px 13px -3px,#D6D6E7 0 -3px 0 inset;box-sizing: border-box;color: #36395A;cursor: pointer;display: inline-flex;font-family: "JetBrains Mono",monospace;height: 40px;justify-content: center;line-height: 1;list-style: none;overflow: hidden;padding-left: 16px;padding-right: 16px;position: relative;text-align: left;text-decoration: none;transition: box-shadow .15s,transform .15s;user-select: none;-webkit-user-select: none;touch-action: manipulation;white-space: nowrap;will-change: box-shadow,transform;font-size: 18px;}.button-30:focus {box-shadow: #D6D6E7 0 0 0 1.5px inset, rgba(45, 35, 66, 0.4) 0 2px 4px, rgba(45, 35, 66, 0.3) 0 7px 13px -3px, #D6D6E7 0 -3px 0 inset;}.button-30:hover {box-shadow: rgba(45, 35, 66, 0.4) 0 4px 8px, rgba(45, 35, 66, 0.3) 0 7px 13px -3px, #D6D6E7 0 -3px 0 inset;transform: translateY(-2px);}.button-30:active {box-shadow: #D6D6E7 0 3px 7px inset;transform: translateY(2px);}</style>
</head>
<body> <canvas id="canvas_line" width="600px" height="600px"></canvas><canvas id="canvas_chess"></canvas><div class="loading-message"><span style="display: none;">正在计算中...</span></div><div class="loading-message"><button onclick="regreat()" class="button-30">悔棋</button></div><div class="logo"><img src="img/logo.png" style="height: 30px;"/></div>
</body>
</html>

  目前的页面样式如下:

在这里插入图片描述

## 添加页面响应式功能

  现在的手机版页面如下,可以发现手机版的棋盘太小、按钮太小、下方的logo太小。

在这里插入图片描述
  于是我们添加响应式功能,在<head>里面添加<meta>头,在<style>里面追加手机页面下的css样式:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
/* 在设备宽度小于600像素时,调整div的大小 */
@media (max-width: 600px) {#canvas_line{width: 100%;}#canvas_chess{width: 100%;}
}

  添加之后,手机版页面就刚好了:

在这里插入图片描述


编写JS

## 获取画布对象与DOM对象

  代码如下:

// 画布
var canvas_chess = document.getElementById("canvas_chess");
var context_chess = canvas_chess.getContext('2d');var canvas_line = document.getElementById("canvas_line");
var context_line = canvas_line.getContext('2d');

  这段代码主要是获取两个画布元素,并分别创建了两个2D绘图上下文对象。这些上下文对象可以用于在画布上进行绘制和操作,例如绘制图形、文本等。

  获取Dom元素是为了得到元素的长宽、偏移量等;获取画布元素是为了绘制图形;获取2个一个是线条容器、一个是棋子容器。

## 定义棋子、棋盘对象

  代码如下:

// 落子状态 'z'为空 'b'为黑 'w'为白
const white_flag = '1';
const black_flag = '-1';
const blank_flag = '0';
// 棋盘边长
const len = 15;class Chess {constructor(x, y, z) {// 横坐标this.x = x;// 纵坐标this.y = y;// 落子状态 '0'为空 '-1'为黑 '1'为白this.z = z;}
}class Board {constructor() {// 棋盘边长this.len = len;// 棋盘棋局状态值 value[len][len]this.value = Array.from(Array(this.len), () => new Array(this.len).fill(blank_flag));// 棋盘棋局状态值 value[len][len]this.chessList = [];}
}

  上述代码定义了两个类,ChessBoard

  Chess 类表示一个棋子,具有横坐标 x、纵坐标 y 和落子状态 z 的属性。
  Board 类表示一个棋盘,具有棋盘边长 len、棋局状态值 value 和棋子列表 chessList 的属性。value 是一个二维数组,用于存储棋盘上每个位置的落子状态。chessList 则是用于存储已下的棋子对象。
  此外,代码中还定义了常量 white_flagblack_flagblank_flag,分别表示白棋、黑棋和空白位置的落子状态。

## 定义绘画对象(重要!!)

  代码如下:

class Draw {constructor(canvas_line, context_line, canvas_chess, context_chess) {// 样式this.style = {// 棋盘边长len : len,// 棋盘线条颜色lineColor : "#555",// 棋盘线条间隔lineWidth : 40,}// 棋盘线条居中时,需要的偏移量this.style['offSet'] = (canvas_line.width - this.style.len * this.style.lineWidth) / 2;// dom对象this.dom = {l : canvas_line,c : canvas_chess}// context对象this.context ={l : context_line,c : context_chess}// 根据线条数、间隔大小 设置棋盘宽、高canvas_chess.height = this.style.len * this.style.lineWidth;canvas_chess.width = this.style.len * this.style.lineWidth; }// 绘制棋盘线条drawChessBoard(){let style = this.style;let color = style.lineColor;let w = style.lineWidth;let o = style.offSet;let len = style.len;let h = w / 2;let c = this.context.l;for(var i=0; i < len; i++){c.strokeStyle = color;c.moveTo(h + i*w + o, h + o);//垂直方向画线c.lineTo(h + i*w + o, h * (2 * len - 1) + o);c.stroke();c.moveTo(h + o, h + i*w + o);//水平方向画线c.lineTo(h * (2 * len - 1) + o , h + i*w + o);c.stroke();}}/*** 绘制单个棋子* @param {*} j 横坐标* @param {*} i 纵坐标* @param {*} k 颜色 黑or白* @param {*} first 是否需要绘制小红点*/drawChess(Chess, first = false){let j = Chess.x;let i = Chess.y;let k = Chess.z;let style = this.style;let w = style.lineWidth;let h = w / 2;let c = this.context.c;c.beginPath();c.arc(h + i*w, h+j*w, h-2, 0, 2 * Math.PI);//绘制棋子var g=c.createRadialGradient(h+i*w,h+j*w,13,h+i*w,h+j*w,0);//设置渐变if(k == black_flag){g.addColorStop(0,'#0A0A0A');//黑棋g.addColorStop(1,'#636766');	}else if(k == white_flag){g.addColorStop(0,'#D1D1D1');//白棋g.addColorStop(1,'#F9F9F9');}c.fillStyle=g;c.fill();c.closePath();if(first){c.fillStyle = 'red';c.fillRect(h*0.75 + i*w, h*0.75+j*w, h/2, h/2)}}// 绘制现有棋子drawChessAll(list) {// 清空棋子canvaslet dom_c = this.dom.c;dom_c.height = dom_c.height;// 依次绘制棋子for(let i in list){if(i == list.length - 1)this.drawChess(list[i], true);elsethis.drawChess(list[i]);}}
}

  上述代码定义了一个名为 Draw 的类。

  Draw 类具有以下属性和方法:

  - 属性:
   - style:包含样式信息的对象,包括棋盘边长 (len)、棋盘线条颜色 (lineColor) 和棋盘线条间隔 (lineWidth)。
   - dom:包含存储 Canvas DOM 对象的属性 lc
   - context:包含存储 Canvas 上下文对象的属性 lc

  - 构造函数:
   - 接受两个 Canvas DOM 对象和对应的上下文对象作为参数,用于初始化 Draw 对象。
   - 在构造函数中,根据传入的参数设置样式、计算偏移量,并设置棋盘 Canvas 的宽度和高度。

  - 方法:
   - drawChessBoard():绘制棋盘线条的方法。这里有好多数学计算,再结合canvas线条绘制的api。
   - drawChess(Chess, first = false):绘制单个棋子的方法。接受 Chess 对象作为参数,包含棋子的横坐标 x、纵坐标 y 和落子状态 z。可选择是否绘制小红点。
   - drawChessAll(list):绘制现有棋子的方法。接受一个棋子对象列表作为参数,依次绘制列表中的棋子。

## 初始化绘制棋盘

  代码如下:

// 棋盘
let board = new Board();
// 绘画器
let draw = new Draw(canvas_line, context_line, canvas_chess, context_chess);// 玩家
let currentPlayer = 1;//绘制棋盘draw.drawChessBoard();

  目前的页面样式如下:

在这里插入图片描述

## 添加点击事件 能够下棋落子

  代码如下:

function clk (e){$("span").css("display","block");canvas_chess.onclick= null;var x = e.offsetY;//相对于棋盘左上角的x坐标var y = e.offsetX;//相对于棋盘左上角的y坐标// var i = Math.floor(x / draw.style.lineWidth);// var j = Math.floor(y / draw.style.lineWidth);var i = Math.floor(x * canvas_chess.width / canvas_chess.offsetWidth / draw.style.lineWidth);var j = Math.floor(y * canvas_chess.width / canvas_chess.offsetWidth / draw.style.lineWidth);if( board.value[i][j] == blank_flag ) {if(currentPlayer == 1){var c = new Chess(i,j,black_flag);board.value[i][j]=black_flag;}else{var c = new Chess(i,j,white_flag);board.value[i][j]=white_flag;}board.chessList.push(c);draw.drawChessAll(board.chessList);if(checkWin(board.chessList, currentPlayer) === true){alert((currentPlayer == 1? "black" : "white") + "win !!");return;}// 切换玩家currentPlayer = (currentPlayer === 1) ? 2 : 1;}else{$("span").css("display","none");canvas_chess.onclick= clk;}}

  这样我们就可以自己交替着下黑子和白子了。于是前端页面基本结束。


继续学习下一篇实战!

  【五子棋实战】第6章 调用接口进行联调


http://www.ppmy.cn/news/531485.html

相关文章

【机器学习】sklearn数据集的使用,数据集的获取和划分

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 sklearn数据集 二、安装sklearn二、获取数据集三、…

国产数据库---Oracle迁移至GBase8a---第一章---数据类型

从今天开始&#xff0c;分享Oracle迁移至GBase8a的一些随笔&#xff0c;希望对大家有帮助。 经过一段时间的分析和整理了基于ORACLE数据库的应用系统向GBase 8a数据库迁移的过程中需要注意的问题和对应的方法。 涉及的内容包括数据库迁移和应用程序迁移两部分。 数据库迁移是…

由oracle数据库转为mysql数据库

项目场景&#xff1a; 由oracle数据库转为mysql数据库 解决方案&#xff1a; 1.在oracle数据库中将所有的Date字段都修改成TIMESTAMP(6)&#xff0c;否则会转换失败。&#xff08;我们是手动修改的&#xff09; 2.利用navicat工具进行数据转换。 ①工具-数据传输 ②数据传输…

oracle编码转换:AL32UTF8-ZHS16GBK

首先查询数据库编码&#xff1a; select userenv(language) from dual; 得到&#xff1a; 【更改编码】 --修改Oracle数据库字符集为utf-8:SQL>conn / as sysdba;SQL>shutdown immediate;SQL>startup mount;SQL>alter system enable restricted session;SQL>alt…

oracle二进制转换字母,如何将oracle二进制数据转换为word文本

现在很多项目和技术支持在线编辑word文档。有控件的和javascript操作的。这里简单的推荐一个在线编辑word文档的控件。 地址&#xff1a;http://www.dianju.cn/p/weboffice/ 在这个控件中&#xff0c;word文档的编辑很好用。但是这里面用到两个方法。word文档和数据库保存的二进…

oracle转mysql数据库

一、在oracle上创建函数&#xff1a; CREATE OR REPLACE procedure convert_date_to_timestamp isv_query_base_sql varchar2(100) : SELECT table_name, column_name, data_type FROM all_tab_cols WHERE table_name ;v_query_table_sql varchar2(150);v_alter_sql varchar2…

石油化工领域生产作业流程合规检测 yolov8

石油化工领域生产作业流程合规检测通过引入yolov8视觉数据智能分析技术&#xff0c;石油化工领域生产作业流程合规检测对生产作业流程进行实时监测和合规性检测&#xff0c;通过与预设标准进行比对&#xff0c;系统能够检测出不合规的操作或异常情况&#xff0c;并及时发出警报…

基础甲骨文2

Promise构造函数&#xff1a; 多层回调函数的相互嵌套&#xff0c;就形成了回调地狱。牵一发而动全身&#xff0c;难以维护&#xff0c;可读性差。 为了解决回调地狱&#xff0c;ES6引入了Promise构造函数概念。 ① Promise 是一个构造函数 我们可以创建 Promise 的实例 co…