Vue和Websocket实现五子棋

功能描述

一个user创建房间,另一个user输入加入的房间号,就可以实现在线的五子棋对战

Vue模块

第一次使用组件化开发,感觉挺有意思的,做成一个个小组件,再将组件拼接在一起实现界面。
组件化开发的好处:

  1. 提高组件的复用 ,减少代码量;
  2. 组件功能更加明确
  3. 组件之间的关系清晰

组件

因为项目较小,组件也不需要复用,所以两个页面就是两个组件。
开始界面:
在这里插入图片描述
代码

<template>
  <div id="big">
    <div id="bg">
      <div id="first">
        <h1>欢迎来到五子棋</h1>
      </div>
      <div id="second">
        <button id="which" class="button green large" @mousedown="Click1" >请选择</button>
        <div id="select">
          <div id="room" >
            <button id="room1" class="button green small" @mousedown="Click2">创建房间</button>
            <button id="room2" class="button green small" @mousedown="Click3">加入房间</button>
          </div>
          <div id="select1">
            <input type="text" class="enter1 text" placeholder="房间号" id="text1">
            <router-link :to="{ name : 'play' }"><button class="enter1 button green littlesmall" @mousedown="submit1">进入</button></router-link>
          </div>

          <div id="select2">
            <input type="text" class="enter2 text" placeholder="房间号" id="text2">
            <router-link :to="{ name : 'play' }"><button class="enter2 button green littlesmall" @mousedown="submit2">进入</button></router-link>
          </div>
        </div>
      </div>
    </div>
  </div>

</template>

<script>
export default {
  name: "Start",
  mounted() {
    let element = document.getElementById('big')
    element.style.height = window.screen.height + 'px'
  },
  methods:{
    Click1(){
      let element=document.getElementById("room");
        element.style.display="block";
    },
    Click2() {
      let element = document.getElementById("select1");
      element.style.display = "block";
    },
    Click3() {
      let element = document.getElementById("select2");
      element.style.display = "block";
    },
    submit1(){
      let number=document.getElementById("text1").innerText;
      this.$global.roomID=number;
      this.$global.role='A';
    },
    submit2(){
      let number=document.getElementById("text2").innerText;
      this.$global.roomID=number;
      this.$global.role='B';

    }

  }
}

</script>

主界面:
在这里插入图片描述
代码

<template>
  <div id="big">
    <div id="gameInfo">
      <div class="infoLine">
        <div class="item">我:</div>
        <div class="item item_chess" id="mychess"></div>
      </div>
      <div class="infoLine">
        <div class="item">当前回合:</div>
        <div id="current" class="item item_chess"></div>
      </div>
    </div>
    <div id="bar" v-on:click="barClick()">
      <img :src=barpng>
    </div>
    <div id="leftBar" class="BarClose">
      <div class="start button"  v-on:click="dis&&start_first()">先手开始</div>
      <div class="start button" v-on:click="dis&&start_last()">
        <!--        <router-link class="router" :to="{ name : 'play' }">后手开始</router-link>-->
        后手开始
      </div>
      <div class="button" v-on:click="send_rollBack">悔棋</div>
      <div class="button" v-on:click="surrender">认输</div>
    </div>
    <div id="main">
      <div id="container">
        <div id="chessboard">
        </div>
        <div v-for="(item,index) in chesses" :key="index" class="chess_off chess" :id="index" v-on:click="setChess(index)">
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import blackchess from '../assets/img/black.png'
import whitechess from '../assets/img/white.png'
import barpng from '../assets/img/bar.png'
function Stack() {
  let items = []
  // 添加元素到栈顶,也就是栈的末尾
  this.push = function (element) {
    items.push(element)
  }
  // 栈的后进先出原则,从栈顶出栈
  this.pop = function () {
    return items.pop()
  }
  // 查看栈顶的元素,访问数组最后一个元素
  this.peek = function () {
    return items[items.length - 1]
  }
  // 检查栈是否为空
  this.isEmpty = function () {
    return items.length == 0
  }
  // 返回栈的长度,栈的长度就是数组的长度
  this.size = function () {
    return items.length
  }
  // 清空栈
  this.clear = function () {
    items = []
  }
  // 打印栈元素
  this.print = function () {
    console.log(items.toString())
  }
}
export default {
  name:'chess',
  data(){
    return{
      barpng : barpng,
      chesses : [
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      ],
      before:[
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
      ],
      chessesdistribution:[
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
      ],
      black: blackchess,
      white: whitechess,
      myturn: false,
      userTag: 'Me',
      roomID:0,
      role:'',
      chessTag_ME: 0,
      chessTag_Other:0,
      chessesColor_Me: null,
      chessesColor_Other: null,
      barOpen:false,
      log: new Stack(),
      socket: '',
      dis: true
    }
  },
  methods:{
    setChess(id){
      //检测是否已经开始游戏
      if (this.chessesColor_Me == null){
        window.alert("请先开始游戏")
      }else{
        let element = document.getElementById(id)
        let i = parseInt(id)
        let x = Math.floor(i/16)
        let y = i - 16*x
        let num = this.chessesdistribution[x][y]
        if (!this.myturn){
          window.alert("当前不是你的回合!")
        }else {
          if (num == 1 | num == -1){
            return
          }else {
            this.log.push(id),
                this.myturn = false
            element.style.cursor = 'unset'
            this.chessesdistribution[x][y] = this.chessTag_ME
            element.style.backgroundImage = 'url("'+this.chessesColor_Me+'")'
            let current = document.getElementById('current')
            if (this.chessTag_ME == 1){
              current.style.background = '#5C5851'
            }else {
              current.style.background = '#C7BEAE'
            }
            //向ws发送一个信息,chessID
            this.sendMessage(2,id)
            if (this.Verify(this.chessesdistribution,this.chessesdistribution[x][y],x,y)){
              window.alert("恭喜你,你胜利了!")
              this.clear()
            }
          }
        }
      }
    },
    setChessByRemo(id){
      let element = document.getElementById(id)
      let i = parseInt(id)
      let x = Math.floor(i/16)
      let y = i - 16*x
      element.style.cursor = 'unset'
      this.chessesdistribution[x][y] = this.chessTag_Other
      element.style.backgroundImage = 'url("'+this.chessesColor_Other+'")'
      this.myturn = true
      let current = document.getElementById('current')
      if (this.chessTag_ME == 1){
        current.style.background = '#C7BEAE'
      }else {
        current.style.background = '#5C5851'
      }
      if (this.Verify(this.chessesdistribution,this.chessesdistribution[x][y],x,y)){
        window.alert("再接再厉,本局游戏你失败了!")
        this.clear()
      }
    },
    Verify(arr,color,x,y){
      //计算左右最大长度
      let temp_length=0;
      for(let i=x;i<=15&&arr[i][y]==color;i++) temp_length++;
      for (let i=x-1;i>=0&&arr[i][y]==color;i--) temp_length++;
      if(temp_length==5)return color;

      //计算上下最大长度
      temp_length=0;
      for(let j=y;j<=15&&arr[x][j]==color;j++) temp_length++;
      for (let j=y-1;j>=0&&arr[x][j]==color;j--) temp_length++;
      if(temp_length==5)return color;

      //计算左上到右下最大长度
      temp_length=0;
      for(let i=x,j=y;i<=15&&j<=15&&arr[i][j]==color;i++,j++) temp_length++;
      for (let i=x-1,j=y-1;i>=0&&j>=0&&arr[i][j]==color;i--,j--) temp_length++;
      if(temp_length==5)return color;

      //计算右上到左下最大长度
      temp_length=0;
      for(let i=x,j=y;i>=0&&j<=15&&arr[i][j]==color;i--,j++) temp_length++;
      for (let i=x+1,j=y-1;i<=15&&j>=0&&arr[i][j]==color;i++,j--) temp_length++;
      if(temp_length==5)return color;

      return 0;

    },
    barClick(){
      let element = document.getElementById('leftBar')
      this.barOpen = !this.barOpen
      if (this.barOpen){
        element.classList.add("BarOpen")
      }else {
        element.classList.remove("BarOpen")
      }

    },
    start_first(){
      //向ws发送一个值
      //将我方设置为白方
      //将我的回合设置为true
      //取消开始的点击事件,更改开始的css
      //设置gamaInfo
      this.sendMessage(3)
      this.chessesColor_Me = this.white
      this.chessesColor_Other = this.black
      this.chessTag_ME = 1
      this.chessTag_Other = -1
      this.myturn = true
      this.dis = false
      let Elements = document.getElementsByClassName('start')
      for (let i=0;i<Elements.length;i++){
        Elements[i].classList.remove('button')
        Elements[i].classList.add('button_unuse')
      }
      let element = document.getElementById('mychess')
      element.style.background = '#C7BEAE'
      let current = document.getElementById('current')
      current.style.background = '#C7BEAE'
    },
    receive_stsrt_first(){
      //将我方设置为黑方
      //取消开始的点击事件,更改开始的css
      this.chessesColor_Me = this.black
      this.chessesColor_Other = this.white
      this.chessTag_ME = -1
      this.chessTag_Other = 1
      this.myturn = false
      this.dis = false
      let Elements = document.getElementsByClassName('start')
      for (let i=0;i<Elements.length;i++){
        Elements[i].classList.remove('button')
        Elements[i].classList.add('button_unuse')
      }
      let element = document.getElementById('mychess')
      element.style.background = '#5C5851'
      let current = document.getElementById('current')
      current.style.background = '#C7BEAE'
    },
    start_last(){
      //向ws发送一个值
      //将我方设置为黑方
      //将我的回合设置为false
      //取消开始的点击事件,更改开始的css
      //设置gamaInfo
      this.sendMessage(5)
      this.chessesColor_Me = this.black
      this.chessesColor_Other = this.white
      this.chessTag_ME = -1
      this.chessTag_Other = 1
      this.myturn = false
      this.dis = false
      let Elements = document.getElementsByClassName('start')
      for (let i=0;i<Elements.length;i++){
        Elements[i].classList.remove('button')
        Elements[i].classList.add('button_unuse')
      }
      let element = document.getElementById('mychess')
      element.style.background = '#5C5851'
      let current = document.getElementById('current')
      current.style.background = '#C7BEAE'
    },
    receive_stsrt_last(){
      //将我方设置为白方
      //取消开始的点击事件,更改开始的css
      this.chessesColor_Me = this.white
      this.chessesColor_Other = this.black
      this.chessTag_ME = 1
      this.chessTag_Other = -1
      this.myturn = true
      this.dis = false
      let Elements = document.getElementsByClassName('start')
      for (let i=0;i<Elements.length;i++){
        Elements[i].classList.remove('button')
        Elements[i].classList.add('button_unuse')
      }
      let element = document.getElementById('mychess')
      element.style.background = '#C7BEAE'
      let current = document.getElementById('current')
      current.style.background = '#C7BEAE'
    },
    getClientHeight() {
      //获取串口大小
      var clientHeight=0;
      if(document.body.clientHeight&&document.documentElement.clientHeight) {
        clientHeight = (document.body.clientHeight<document.documentElement.clientHeight)?document.body.clientHeight:document.documentElement.clientHeight;
      }
      else {
        clientHeight = (document.body.clientHeight>document.documentElement.clientHeight)?document.body.clientHeight:document.documentElement.clientHeight;
      }
      return clientHeight;
    },
    getClientWidth() {
      //获取串口大小
      var clientWidth=0;
      if(document.body.clientWidth&&document.documentElement.clientWidth) {
        clientWidth = (document.body.clientWidth<document.documentElement.clientWidth)?document.body.clientWidth:document.documentElement.clientWidth;
      }
      else {
        clientWidth = (document.body.clientWidth>document.documentElement.clientWidth)?document.body.clientWidth:document.documentElement.clientWidth;
      }
      return clientWidth;
    },
    send_rollBack(){
      if (this.log.isEmpty()){
        window.alert('已回到初始状态')
      }else {
        //向ws发送一个rb消息
        //改变最后一次落子,改变双方的turn状态
        this.sendMessage(4)
        this.rollBack()
      }
    },
    rollBack(){
      this.myturn = !this.myturn
      let last = this.log.pop()
      let element = document.getElementById(last)
      let i = parseInt(last)
      let x = Math.floor(i/16)
      let y = i - 16*x
      element.style.cursor = 'pointer'
      this.chessesdistribution[x][y] = 0
      element.style.backgroundImage = 'none'
      let current = document.getElementById('current')
      if (this.myturn){
        if (this.chessTag_ME == 1){
          current.style.background = '#C7BEAE'
        }else {
          current.style.background = '#5C5851'
        }
      }else{
        if (this.chessTag_ME == 1){
          current.style.background = '#5C5851'
        }else {
          current.style.background = '#C7BEAE'
        }
      }
    },
    receiver_rollBack(){
      this.rollBack()
      window.alert("对方发起悔棋操作")
    },
    sendMessage(type, id){
      let socket = this.socket
      let to = ''
      if (this.role=='A'){
        to = 'B'
      }else to = 'A'
      socket.send(JSON.stringify({
        uid:this.roomID+this.role,
        to:this.roomID+to,
        type: type,
        id: id
      }));
    },
    surrender(){
      //将本地的数据恢复到初始状态
      this.clear()
      //发送ws信息
      this.sendMessage(6)
    },
    clear(){
      this.chessesdistribution = this.before
      let elements = document.getElementsByClassName("chess")
      for(var i=0;i<elements.length;i++){
        elements[i].style.cursor = 'pointer'
        elements[i].style.backgroundImage = 'none'
      }
      this.log.clear()
      this.myturn = false
      this.dis = true
      let current = document.getElementById('current')
      current.style.background = 'rgba(255,255,255,0)'
      let element = document.getElementById('mychess')
      element.style.background = 'rgba(255,255,255,0)'
      let Elements = document.getElementsByClassName('start')
      for (let i=0;i<Elements.length;i++){
        Elements[i].classList.remove('button_unuse')
        Elements[i].classList.add('button')
      }
      this.chessTag_ME = 0
      this.chessTag_Other = 0
      this.chessesColor_Me =  null
      this.chessesColor_Other = null
    },
    receive_surrender(){
      this.clear()
    },
    //连接服务器
    conWebSocket(){
      let vm = this;
      if(window.WebSocket){
        vm.socket = new WebSocket('ws://localhost:8101');
        let socket = vm.socket;

        socket.onopen = function(){
          console.log("连接服务器成功");
          vm.sendMessage(1)
        }
        socket.onclose = function(){
          console.log("服务器关闭");
        }
        socket.onerror = function(){
          console.log("连接出错");
        }
        // 接收服务器的消息
        socket.onmessage = function(e){
          let message = JSON.parse(e.data);
          console.log(message)
          switch (message.type) {
            case 2:
              vm.setChessByRemo(message.chessID)
              break
            case 3:
              vm.receive_stsrt_first()
              break
            case 4:
              vm.receiver_rollBack()
              break
            case 5:
              vm.receive_stsrt_last()
              break
            case 6:
              console.log("=======6====")
              vm.receive_surrender()
              break

          }
          this.setChessByRemo(message.id)
        }
      }
    }
  },
  mounted() {
    window.vue = this
    this.role = this.$global.role
    this.roomID = this.$global.roomID
    this.conWebSocket()
    let element = document.getElementById('big')
    element.style.height = this.getClientHeight() + 'px'
    element.style.width = this.getClientWidth() + 'px'
    let elements = document.getElementsByClassName('chess')
    for (let i=0;i<elements.length;i++){
      let x = Math.floor(i/16)
      let y = (i - 16*x)*40
      let x_ = x*40
      elements[i].style.position = 'absolute'
      elements[i].style.top = x_+'px'
      elements[i].style.left = y+'px'
      
    }
  }
}
</script>

css代码太长就没有放上来了,可在我的资源里面查看

路由设置

import Vue from 'vue'

import Router from 'vue-router'

Vue.use(Router)

import main from "@/components/main";
import Start from "@/components/Start";
var router = new Router({
        routes: [
            {
                path:'/',
                component:Start,
                name: 'log',
                meta:{
                    title:"在线五子棋——进入房间"
                }
            },{
                path:'/play',
                component:main,
                name: 'play',
                meta:{
                    title: "在线五子棋"
                }
            }
        ]
    }
)

export default router

Websocket后端

每个user都与websocket后端建立一个websocket连接,下棋信息会由User—>后端—>User过程实现

var ws = require("nodejs-websocket");
console.log("开始建立连接...")
let conns = {};
function boardcast(obj) {
    console.log(obj)
    conns[obj.user].sendText(JSON.stringify(obj));
    return;
}
var server = ws.createServer(function(conn){
    conn.on("text", function (obj) {
        obj = JSON.parse(obj);
        conns[obj.uid] = conn;
        console.log(obj)
        switch(obj.type){
            // 创建连接
            case 1:
                console.log("获取到"+obj.uid+"的连接")
                break;
            // 发送消息
            case 2:
                console.log("==========2========")
                boardcast({
                    type: 2,
                    user: obj.to,
                    chessID:obj.id
                });
                break;
            //先手信息
            case 3:
                boardcast({
                    type:3,
                    user:obj.to
                });
                break;
            //悔棋
            case 4:
                boardcast({
                    type:4,
                    user:obj.to
                })
                break
            //后手信息
            case 5:
                boardcast({
                    type:5,
                    user:obj.to
                })
                break
            //认输
            case 6:
                boardcast({
                    type:6,
                    user:obj.to
                })
                break
        }
    })
    conn.on("close", function () {
        console.log("关闭连接")
    });
    conn.on("error", function () {
        console.log("异常关闭")
    });
}).listen(8101)
console.log("WebSocket建立完毕")

感言

这是我大二的一个课程设计,前后端分离对小组来说就很容易分工,Vue的组件化开发很牛b,希望以后越做越好。
项目代码都在以下文件:https://download.csdn.net/download/weixin_45912825/18806886

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现Vue3的Websocket实时报警弹窗,你可以按照以下步骤进行操作: 1. 安装并引入Vue3的Websocket插件,例如vue-native-websocket。 2. 在Vue3的组件中使用该插件来建立Websocket连接,例如: ``` <template> <div> <h1>实时报警弹窗</h1> <ul> <li v-for="(alert, index) in alerts" :key="index"> {{ alert }} </li> </ul> </div> </template> <script> import VueNativeSock from 'vue-native-websocket' export default { data() { return { alerts: [] } }, mounted() { this.$connect('ws://localhost:8080/alerts') }, methods: { addAlert(alert) { this.alerts.push(alert) } }, created() { this.$options.sockets.onmessage = (message) => { this.addAlert(message.data) } } } </script> ``` 3. 在服务器端建立Websocket服务,例如使用Node.jsWebSocket库: ``` const WebSocket = require('ws') const wss = new WebSocket.Server({ port: 8080 }) wss.on('connection', (ws) => { console.log('客户端已连接') ws.on('message', (message) => { console.log(`收到消息:${message}`) wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(message) } }) }) }) ``` 4. 在服务端不断地发送报警信息到客户端,例如: ``` setInterval(() => { const alert = { type: 'warning', message: '门未关好,请注意' } wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify(alert)) } }) }, 5000) ``` 这样就可以在Vue3的组件中实时接收并显示报警信息了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值