【五子棋实战】第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;
    }
  }

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




相关文章
|
9月前
|
前端开发 算法 Java
【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
伪类:伪类这个叫法源自于它们跟类相似,但实际上并没有类会附加到标记中的标签上。 伪类分为两种(以及新增的伪类选择器): UI伪类:会在HTML元素处于某种状态时(例如:鼠标指针位于连接上),为该元素应用CSS样式。 :hover 结构化伪类:会在标记中存在某种结构上的关系时 例如: 某元素是一组元素中的第一个或最后一个,为该元素应用CSS样式。 :not和:target(CSS3新增的两个特殊的伪类选择器)
1168 2
|
11月前
|
JSON 监控 前端开发
AMIS:百度开源的前端低代码神器,18.4k star 背后的开发效率提升利器
AMIS(前端低代码框架)是百度开源的低代码前端框架,基于纯 JSON 配置即可生成完整后台页面,包括表单、表格、图表、CRUD 列表,支持可视化拖拽编辑。,星标数已达 18.4k,百度内部已沉淀超过 5 万个页面,广泛应用于审核系统、数据管理后台、模型监控等落地场景
1829 0
|
10月前
|
人工智能 前端开发 JavaScript
前端工程化演进之路:从手工作坊到AI驱动的智能化开发
前端工程化演进之路:从手工作坊到AI驱动的智能化开发
1042 19
前端工程化演进之路:从手工作坊到AI驱动的智能化开发
|
前端开发 JavaScript 索引
前端性能优化:虚拟滚动技术原理与实战
前端性能优化:虚拟滚动技术原理与实战
1650 80
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
787 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
存储 消息中间件 前端开发
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
校园圈子系统校园论坛小程序采用uni-app前端框架,支持多端运行,结合PHP后端(如ThinkPHP/Laravel),实现用户认证、社交关系管理、动态发布与实时聊天功能。前端通过组件化开发和uni.request与后端交互,后端提供RESTful API处理业务逻辑并存储数据于MySQL。同时引入Redis缓存热点数据,RabbitMQ处理异步任务,优化系统性能。核心功能包括JWT身份验证、好友系统、WebSocket实时聊天及活动管理,确保高效稳定的用户体验。
770 4
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
|
IDE 前端开发 开发工具
用通义灵码IDE做产品高保真原型和前端页面
通义灵码IDE助力高效开发,告别传统Axure原型图的繁琐沟通。通过该工具可直接生成高保真产品原型与前端页面,大幅提升客户确认效率及满意度。现已将相关演示发布至B站(https://www.bilibili.com/video/BV18qT7ziEb7/?vd_source=dc6a6864c895818db6ce4170d50b3557),欢迎体验!用直观操作代替反复说明,让交付更流畅。
|
安全 前端开发 开发工具
【01】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-优雅草卓伊凡拟开发一个一站式家政服务平台-前期筹备-暂定取名斑马家政软件系统-本项目前端开源-服务端采用优雅草蜻蜓Z系统-搭配ruoyi框架admin后台-全过程实战项目分享-从零开发到上线
【01】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-优雅草卓伊凡拟开发一个一站式家政服务平台-前期筹备-暂定取名斑马家政软件系统-本项目前端开源-服务端采用优雅草蜻蜓Z系统-搭配ruoyi框架admin后台-全过程实战项目分享-从零开发到上线
875 5
【01】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-优雅草卓伊凡拟开发一个一站式家政服务平台-前期筹备-暂定取名斑马家政软件系统-本项目前端开源-服务端采用优雅草蜻蜓Z系统-搭配ruoyi框架admin后台-全过程实战项目分享-从零开发到上线
|
JSON 前端开发 API
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
1085 5
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
|
JSON 前端开发 数据可视化
前端开发者狂喜!30K star开源组件库,界面美观度/开发速度双碾压!
嗨,大家好,我是小华同学。Layui 是一款开源前端 UI 组件库,具有极简设计、强大功能和卓越性能,支持布局、表单、表格、弹层等六大模块,组件高度可定制。它无需复杂构建工具,直接面向浏览器开发,极大提升开发效率与界面美观度。适合新手和老手,快来试试吧!
897 0

热门文章

最新文章

  • 1
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
    1262
  • 2
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(九):强势分析Animation动画各类参数;从播放时间、播放方式、播放次数、播放方向、播放状态等多个方面,完全了解CSS3 Animation
    573
  • 3
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
    434
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(七):学习ransform属性;本文学习 rotate旋转、scale缩放、skew扭曲、tanslate移动、matrix矩阵 多个参数
    436
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
    551
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
    728
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
    1414
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(三):元素继承关系、层叠样式规则、字体属性、文本属性;针对字体和文本作样式修改
    315
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
    1168
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
    509