# 战舰游戏

# 展示

基于 vue 开发,具体代码请看vue 写法

输入
重置

# 原生 js 代码

<div class="continuar">
  <table cellpadding="0" cellspacing="0" id='tab'>
   tr*7>td*7
  </table>
  <div class="enter">
    <input type="text" placeholder="A0" maxlength="2" id="coordinate" value="">
    <div class="btn" id='btnEnter'>输入</div>
  </div>
</div>
1
2
3
4
5
6
7
8
9
* {
  margin: 0;
  padding: 0;
}
body {
  background-color: black;
}
.continuar {
  margin: 0;
  width: 650px;
  position: relative;
  height: 650px;
  background: url('../images/board.jpg') no-repeat;
  background-size: contain;
}

table {
  margin: 0 auto;
  padding-top: 62px;
}

tr td {
  width: 60px;
  height: 60px;
  border: 0px solid rgb(21, 172, 16);
}
td.ship {
  background: url('../images/ship.png') no-repeat;
  background-size: contain;
  background-position: center;
}
td.miss {
  background: url('../images/miss.png') no-repeat;
  background-size: contain;
  background-position: center;
}
.enter {
  position: absolute;
  right: 14%;
  bottom: 0;
  display: flex;
  padding: 20px;
}
.enter input {
  height: 35px;
  color: #000000;
  background-color: rgb(159, 255, 48);
  display: block;
  float: left;
  border: 0;
}
.enter .btn {
  height: 25px;
  float: left;
  padding: 0 5px;
  cursor: pointer;
  font-size: 12px;
  color: aliceblue;
  margin-left: 5px;
  line-height: 25px;
  user-select: none;
  text-align: center;
  background-color: #41510d;
  border: 5px solid #46e234;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
window.onload = function() {
  let btnEnter = document.getElementById('btnEnter');
  let coordinate = document.getElementById('coordinate');
  // 给节点添加点击事件
  btnEnter.onclick = btn;
  coordinate.onkeypress = key;
  function key(e) {
    // 监听`enter`键是否被点击
    if (e.charCode === 13) {
      btn();
    }
  }
  // 转化坐标
  let digital = { A: 0, B: 7, C: 14, D: 21, E: 28, F: 35, G: 42 };
  // 使用随机数,初始化战舰位置
  let ships = {
    0: Math.floor(Math.random() * 48),
    1: Math.floor(Math.random() * 48),
    2: Math.floor(Math.random() * 48),
  };
  console.log(ships);
  // 获取所有的`td`
  function btn() {
    console.log(coordinate.value);
    let patt1 = new RegExp(/^[a-g][0-6]/i);
    if (patt1.test(coordinate.value)) {
      // 截取字符串中的首位,将其转化为大写字母
      let coordinateText = coordinate.value[0].toUpperCase();
      // 玩家输入的战舰坐标
      let coordinateNumber =
        Number.parseInt(digital[coordinateText]) +
        Number.parseInt(coordinate.value[1]);
      // 获取所有名为 `td` 的节点
      let tds = document.getElementsByTagName('td');
      // 判断玩家输入的坐标上,是否有战舰存在,如果有的话,就击沉战舰
      if (
        ships[0] === coordinateNumber ||
        ships[1] === coordinateNumber ||
        ships[2] === coordinateNumber
      ) {
        // 击沉战舰
        tds[coordinateNumber].setAttribute('class', 'ship');
      } else {
        // 没有击沉战舰
        tds[coordinateNumber].setAttribute('class', 'miss');
      }
    } else {
      alert('请输入正确的坐标;\n如: A6!');
    }
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# vue 写法

这里我做了一点改进,增加直接点击区域替换背景图标,详细功能请点击展示

<template>
  <div class="continuar">
    <div class="table">
      <div v-for="(item,index) in letter" :key="index" class="tr">
        <div v-for="i in [0,1,2,3,4,5,6]" :key='i' ref="td" @click="btn(item+i,digital[item]+i)"
          class="td">
        </div>
      </div>
    </div>
    <div class="enter">
      <input type="text" placeholder="A0" v-model="enter" maxlength="2"
        @keyup.enter="btn" id="coordinate" value="">
      <div class="btn" @click="btn">输入</div>
      <div class="btn reload" @click="reload">重置</div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      letter: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
      digital: { A: 0, B: 7, C: 14, D: 21, E: 28, F: 35, G: 42 },
      enter: '',
      ships: {
        0: Math.floor(Math.random() * 48),
        1: Math.floor(Math.random() * 48),
        2: Math.floor(Math.random() * 48),
      },
    };
  },
  methods: {
    /**
     * 获取点击元素在父元素中的下标
     * @param {String} enters 坐标~~如:A6
     * @param {Number} index 被点击目标的下标
     */
    btn(enters, index) {
      // 创建正则,匹配输入坐标是否符合格式要求如: A6
      let patt1 = new RegExp(/^[a-g][0-6]/i);
      let coordinateNumber, coordinateText;
      if (enters.length == 2) {
        // 同步更新输入框中的坐标,可关闭
        this.enter = enters;
        // 判断玩家输入的坐标上,是否有战舰存在,如果有的话,就击沉战舰
        this.setAttribute(index);
        return;
      } else if (patt1.test(this.enter)) {
        // 截取字符串中的首位,将其转化为大写字母
        coordinateText = this.enter[0].toUpperCase();
        // 玩家输入的战舰坐标
        coordinateNumber =
          Number.parseInt(this.digital[coordinateText]) +
          Number.parseInt(this.enter[1]);
        // 判断玩家输入的坐标上,是否有战舰存在,如果有的话,就击沉战舰
        this.setAttribute(coordinateNumber);
      } else {
        alert('请输入正确的坐标;\n如: A6!');
      }
    },
    /**
     * 为目标元素替换类名
     * @param {Number} coordinateNumber 被点击目的的下标: 例如 45
     */
    setAttribute(coordinateNumber) {
      let getClassName = this.$refs.td[coordinateNumber]
        .getAttribute('class')
        .split(' ');
      if (getClassName.length > 1) {
        alert(`该区域已经${getClassName[0]},请切换其他空白区域!`);
        return;
      }

      if (
        this.ships[0] === coordinateNumber ||
        this.ships[1] === coordinateNumber ||
        this.ships[2] === coordinateNumber
      ) {
        // 击沉战舰
        this.$refs.td[coordinateNumber].setAttribute('class', 'ship td');
      } else {
        // 没有击沉战舰
        this.$refs.td[coordinateNumber].setAttribute('class', 'miss td');
      }
    },
    /**
     * 重置this.data中部分kay的value
     */
    reload() {
      this.enter = '';
      for (let i in this.ships) {
        this.ships[i] = Math.floor(Math.random() * 48);
      }
      for (let i in this.$refs.td) {
        this.$refs.td[i].setAttribute('class', 'td');
      }
    },
  },
};
</script>
<style scoped>
.continuar {
  margin: 0;
  width: 650px;
  position: relative;
  height: 650px;
  background: url('/images/js/2018_11_02/board.jpg') no-repeat;
  background-size: contain;
}

.table {
  margin: 0 auto;
  padding-top: 62px;
  padding-left: 106px;
}

.tr {
  display: flex;
}

.tr .td {
  flex: 0 0 62px;
  height: 61px;
  line-height: 61px;
  text-align: center;
  color: white;
  box-sizing: border-box;
}

.td.ship {
  background: url('/images/js/2018_11_02/ship.png') no-repeat;
  background-size: 70%;
  background-position: center;
}

.td.miss {
  background: url('/images/js/2018_11_02/miss.png') no-repeat;
  background-size: 70%;
  background-position: center;
}

.enter {
  position: absolute;
  right: 5px;
  top: 5px;
  display: flex;
  padding: 5px;
  margin-left: 0;
  margin-right: auto;
}

.enter input {
  height: 35px;
  color: #000000;
  background-color: rgb(159, 255, 48);
  display: block;
  float: left;
  border: 0;
}

.enter .btn {
  height: 25px;
  float: left;
  padding: 0 5px;
  cursor: pointer;
  font-size: 12px;
  color: aliceblue;
  margin-left: 5px;
  line-height: 25px;
  user-select: none;
  text-align: center;
  background-color: #41510d;
  border: 5px solid #46e234;
}
</style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
Last Updated: 11/2/2018, 4:24:41 PM