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

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

页面设计原则


  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>


  目前的页面样式如下:


image.png


## 添加页面响应式功能


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


image.png


  于是我们添加响应式功能,在<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 = [];
  }
}


 上述代码定义了两个类,Chess 和 Board。


 Chess 类表示一个棋子,具有横坐标 x、纵坐标 y 和落子状态 z 的属性。


 Board 类表示一个棋盘,具有棋盘边长 len、棋局状态值 value 和棋子列表 chessList 的属性。value 是一个二维数组,用于存储棋盘上每个位置的落子状态。chessList 则是用于存储已下的棋子对象。


 此外,代码中还定义了常量 white_flag、black_flag 和 blank_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) {
    // 清空棋子canvas
    let 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);
      else
        this.drawChess(list[i]);
    }
  }
}


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


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


 - 属性:


  - style:包含样式信息的对象,包括棋盘边长 (len)、棋盘线条颜色 (lineColor) 和棋盘线条间隔 (lineWidth)。


  - dom:包含存储 Canvas DOM 对象的属性 l 和 c。


  - context:包含存储 Canvas 上下文对象的属性 l 和 c。



 - 构造函数:


  - 接受两个 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;
    }
  }

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




相关文章
|
23天前
|
前端开发 JavaScript API
(前端3D模型开发)网页三维CAD中加载和保存STEP模型
本文介绍了如何使用`mxcad3d`库在网页上实现STEP格式三维模型的导入与导出。首先,通过官方教程搭建基本项目环境,了解核心对象如MxCAD3DObject、Mx3dDbDocument等的使用方法。接着,编写了加载和保存STEP模型的具体代码,包括HTML界面设计和TypeScript逻辑实现。最后,通过运行项目验证功能,展示了从模型加载到保存的全过程。此外,`mxcad3d`还支持多种其他格式的三维模型文件操作。
|
2月前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
10天前
|
开发框架 前端开发 JavaScript
uniapp开发鸿蒙,是前端新出路吗?
相信不少前端从业者一听uniapp支持开发鸿蒙Next后非常振奋。猫林老师作为7年前端er也是非常激动,第一时间体验了下。在这里也给大家分享一下我的看法
55 17
|
3天前
|
开发框架 小程序 前端开发
圈子社交app前端+后端源码,uniapp社交兴趣圈子开发,框架php圈子小程序安装搭建
本文介绍了圈子社交APP的源码获取、分析与定制,PHP实现的圈子框架设计及代码编写,以及圈子小程序的安装搭建。涵盖环境配置、数据库设计、前后端开发与接口对接等内容,确保平台的安全性、性能和功能完整性。通过详细指导,帮助开发者快速搭建稳定可靠的圈子社交平台。
|
15天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
49 3
|
13天前
|
前端开发 搜索推荐 安全
陪玩系统架构设计陪玩系统前后端开发,陪玩前端设计是如何让人眼前一亮的?
陪玩系统的架构设计、前后端开发及前端设计是构建吸引用户、功能完善的平台关键。架构需考虑用户需求、技术选型、安全性等,确保稳定性和扩展性。前端可选用React、Vue或Uniapp,后端用Spring Boot或Django,数据库结合MySQL和MongoDB。功能涵盖用户管理、陪玩者管理、订单处理、智能匹配与通讯。安全性方面采用SSL加密和定期漏洞扫描。前端设计注重美观、易用及个性化推荐,提升用户体验和平台粘性。
43 0
|
30天前
|
存储 前端开发 JavaScript
前端状态管理:Vuex 核心概念与实战
Vuex 是 Vue.js 应用程序的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。本教程将深入讲解 Vuex 的核心概念,如 State、Getter、Mutation 和 Action,并通过实战案例帮助开发者掌握在项目中有效使用 Vuex 的技巧。
|
2月前
|
前端开发 数据安全/隐私保护
.自定义认证前端页面
.自定义认证前端页面
14 1
.自定义认证前端页面
|
2月前
|
前端开发 JavaScript 搜索推荐
前端懒加载:提升页面性能的关键技术
前端懒加载是一种优化网页加载速度的技术,通过延迟加载非首屏内容,减少初始加载时间,提高用户访问体验和页面性能。
|
2月前
|
Web App开发 缓存 监控
前端性能优化实战:从代码到部署的全面策略
前端性能优化实战:从代码到部署的全面策略
36 1