游戏介绍:随机生成4个数字,通过加减乘除,是最后的结果为24。
不足之处:
- 随机生成的数字可能不能通过运算得出结果24,你们也可以在我的基础上进行修改。
- 我的“确认”按钮每次只能进行两个数的运算。
闲谈:这是我这年暑假做的(挺久的),感觉还不是很成熟。很久没写了,都有些生疏了(^-^)
一、游戏布局
1.1页面布局介绍

不包含标题的情况下,大体上有三个版块:
- 第一个版块包含了时间、解决问题数、规则
- 第二个版块包含了运算需要的数字和字符
- 第三个版块包含了主要的功能按钮
1.2代码
下面是我部分代码(后面有我的详细介绍)
1<template> 2<div class="box_one"> 3 <div class="title">游戏</div> 4 <div class="box_two"> 5 <div class="time_num">时间:{{ time }}</div> 6 <div class="ques_num">已解决:{{number}}</div> 7 <button class="tip_btn" @click="tipHandle">规则</button> 8 <div class="tip" v-if="show_tip"> 9 <div class="tip_c">使用给定的4个数字(每个数字必须且只能使用一次),通过加、减、乘、除和括号运算,使最终结果等于24。</div> 10 <button class="con_c" @click="conHandle">关闭</button> 11 </div> 12 <br> 13 </div> 14 <div class="content"> 15 <div class="num"> 16 <div class="num_s" v-for="(item,index) in texts" :key="index"> 17 <button class="num_item" @click="numHandle(index)">{{ item }}</button> 18 </div> 19 </div> 20 <div class="opener"> 21 <div class="opener_i" v-for="(opener,index) in openers" :key="index"> 22 <button class="opener_item" @click="openerHandle(index)">{{ opener }}</button> 23 </div> 24 </div> 25 <div class="input"> 26 <div class="input_t">{{ str }}</div> 27 <button class="can_btn" @click="canHandle">确认</button> 28 </div> 29 </div> 30 <div class="select"> 31 <div class="sel_one"> 32 <button class="next_btn" @click="nextHandle">下一题</button> 33 <button class="clear_btn" @click="clearHandle">清空</button> 34 </div> 35 <div> 36 <button class="start_btn" @click="startHandle">开始</button> 37 </div> 38 <div class="sel_two"> 39 <button class="restart_btn" @click="renewHandle">计时</button> 40 <button class="stop_btn" @click="stopHandle">{{ btn }}</button> 41 </div> 42 43 </div> 44</div> 45</template>
1.3具体语法介绍
1)v-for: 这个类似于for循环,在vue中v-for 是一个用于渲染列表的指令
我这里使用v-for渲染随机生成的数字,和运算符。这样很大程度上节省了较多时间去创建更多的容器、标签。
1<div class="num_s" v-for="(item,index) in texts" :key="index"> 2 <button class="num_item" @click="numHandle(index)">{{ item }}</button> 3 </div>
- texts是我在<script>中定义的数组
- item:当前遍历到的数组元素值
- index:当前元素的索引位置(从0开始)
- texts:数据源数组
- :key="index":类似于数据库中表的主键,都是具有唯一标识。使用索引作为 key
- {{item}}:显示当前遍历的内容
**2)v-if:**用于条件渲染一块内容,这块内容只会在指令的表达式返回真值时才被渲染。
我这里用v-if来显示规则,"show_tip"这个变量初始化为false(不显示具体规则),只有点击“规则”才赋值为true
1<div class="tip" v-if="show_tip"> 2 <div class="tip_c">使用给定的4个数字(每个数字必须且只能使用一次),通过加、减、乘、除和括号运算,使最终结果等于24。</div> 3 <button class="con_c" @click="conHandle">关闭</button> 4 </div>
二、游戏中按钮功能
2.1按钮功能介绍
按钮大概有7个
- 规则:通过"show_tip"变量来确定是否显示规则。
1 tipHandle() { //规则展开 2 this.show_tip = true 3 }, 4 conHandle() { //规则关闭 5 this.show_tip = false 6 },
- 数字/运算符:处理用户选择的数字和运算符
1 numHandle(index) { //对数字的处理 2 if (this.str1 == 0) 3 this.str1 = this.texts[index] //赋值 4 else 5 this.str2 = this.texts[index] 6 7 this.str = this.str + String(this.texts[index]) //转换成字符类型,str是要在文本框显示的 8 this.texts.splice(index, 1) //对选择的字符进行删除 9 }, 10 openerHandle(index) { //对运算符的处理 11 this.open = this.openers[index] 12 this.str = this.str + open 13 },
- 确认:通过用户确定的操作数和运算符,进行计算。
1canHandle() { //计算 2 if (this.str1 > 0 && this.str1 < 10 && this.str2 > 0 && this.str2 < 10 && this.open !== '') { 3 switch (this.open) { 4 case '+': 5 this.sum = this.str1 + this.str2; 6 break; 7 case '-': 8 this.sum = this.str1 - this.str2; 9 break; 10 case '*': 11 this.sum = this.str1 * this.str2; 12 break; 13 case '/': 14 this.sum = this.str1 / this.str2; 15 break; 16 } 17 18 this.texts.push(this.sum) 19 this.str1 = 0 //计算后数值又回到初始状态 20 this.str2 = 0 21 this.str = "" 22 if (this.texts.length == 1 && this.sum == 24) { 23 ++this.number; //已解决的数量加1 24 this.nextHandle() //下一题(后面有介绍) 25 } 26 } 27 else{ 28 alert('不能计算') 29 this.clearHandle() //清空,也就是重置(后面有介绍) 30 } 31 }, 32 } 33}
- 下一题:生成随机数
1nextHandle() { 2 //this.totalTime=0; 每次点击下一题,计时要重新开始(我认为没必要) 3 let i = 4; 4 for (let j = 0; j < i; j++) { 5 this.texts[j] = Math.floor(Math.random() * (9)) + 1 6 //console.log(texts[0]) 7 } 8 this.copy = this.texts 9 this.sum = 0 10 this.str = "" 11 this.copy = [...this.texts] //浅拷贝,copy这个数组是独立的,就是方便重置的。 12 //this.copy = this.texts 这是引用赋值,对texts操作也会影响到copy,这里不能使用 13 },
-
- Math.random() * 9 生成 0-8.999... 的随机数
- Math.floor() 向下取整得到 0-8
- +1 后得到 1-9
- 清空
1clearHandle() { 2 this.texts = [...this.copy] //重置回之前的状态 3 this.str = "" 4 this.str1 = 0 5 this.str2 = 0 6 },
- 计时:
1renewHandle() { 2 if (!this.isok) return; 3 if (this.isok) { 4 this.totalTime++; 5 const min = Math.floor(this.totalTime / 60); 6 const sec = Math.floor(this.totalTime % 60); 7 this.time = [`${min.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`](function toString() { [native code] }); 8 } 9 setTimeout(() => this.renewHandle(), 1000); //1000是毫秒,也就是1秒。1秒后调用自身 10 },
- isok:来控制计时器是否启动
- totalTime++: 累计经过的秒数
- min: 分钟数(总秒数÷60取整)
- sec: 秒数(总秒数÷60的余数)
- padStart(2, '0'): 补零操作,确保显示为两位数
- toString():转换成字符串
- setTimeout():异步执行不会阻塞后续代码,在指定毫秒后执行回调函数
- 暂停:
1stopHandle() { 2 this.btn = this.isok ? "开始" : "暂停" 3 this.isok = !this.isok; 4 this.renewHandle(); 5 6 },
- 开始:
1startHandle() { 2 this.totalTime = 0 3 this.renewHandle() //重新计算 4 this.nextHandle() //随机数生成 5 },
2.2代码
1<script> 2export default { 3 data() { 4 return { 5 time: "00:00", 6 totalTime: 0, 7 isok: true, 8 number: 0, 9 show_tip: false, 10 num: [1, 2, 3, 4, 5, 6, 7, 8, 9], 11 openers: ['+', '-', '*', '/'], 12 texts: [0, 0, 0, 0], 13 copy: [0, 0, 0, 0], 14 btn: "暂停", 15 str1: 0, 16 str2: 0, 17 sum: 0, 18 str: "", 19 open: "" 20 } 21 }, 22 23 methods: { 24 tipHandle() { 25 this.show_tip = true 26 }, 27 conHandle() { 28 this.show_tip = false 29 }, 30 renewHandle() { 31 if (!this.isok) return; 32 if (this.isok) { 33 this.totalTime++; 34 const min = Math.floor(this.totalTime / 60); 35 const sec = Math.floor(this.totalTime % 60); 36 this.time = [`${min.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`](function toString() { [native code] }); 37 } 38 setTimeout(() => this.renewHandle(), 1000); 39 }, 40 nextHandle() { 41 //this.totalTime=0; 42 let i = 4; 43 for (let j = 0; j < i; j++) { 44 this.texts[j] = Math.floor(Math.random() * (9)) + 1 45 //console.log(texts[0]) 46 } 47 48 this.sum = 0 49 this.str = "" 50 this.copy = [...this.texts] 51 //this.copy = this.texts 这是引用赋值,对texts操作也会影响到copy,这里不能使用 52 }, 53 clearHandle() { 54 this.texts = [...this.copy] 55 this.str = "" 56 this.str1 = 0 57 this.str2 = 0 58 }, 59 stopHandle() { 60 this.btn = this.isok ? "开始" : "暂停" 61 this.isok = !this.isok; 62 this.renewHandle(); 63 64 }, 65 startHandle() { 66 this.totalTime = 0 67 this.renewHandle() 68 this.nextHandle() 69 }, 70 numHandle(index) { 71 if (this.str1 == 0) 72 this.str1 = this.texts[index] 73 else 74 this.str2 = this.texts[index] 75 76 this.str = this.str + String(this.texts[index]) 77 this.texts.splice(index, 1) 78 }, 79 openerHandle(index) { 80 this.open = this.openers[index] 81 this.str = this.str + this.open 82 }, 83 canHandle() { 84 if (this.str1 > 0 && this.str1 < 10 && this.str2 > 0 && this.str2 < 10 && this.open !='') { 85 switch (this.open) { 86 case '+': 87 this.sum = this.str1 + this.str2; 88 break; 89 case '-': 90 this.sum = this.str1 - this.str2; 91 break; 92 case '*': 93 this.sum = this.str1 * this.str2; 94 break; 95 case '/': 96 this.sum = this.str1 / this.str2; 97 break; 98 } 99 100 this.texts.push(this.sum) 101 this.str1 = 0 102 this.str2 = 0 103 this.str = "" 104 if (this.texts.length == 1 && this.sum == 24) { 105 ++this.number; 106 this.nextHandle() 107 } 108 } 109 else{ 110 alert('不能计算') 111 this.clearHandle() 112 } 113 }, 114 } 115} 116</script>
三、源代码
全部代码,包括css
1<template> 2 <div class="box_one"> 3 <div class="title">游戏</div> 4 <div class="box_two"> 5 <div class="time_num">时间:{{ time }}</div> 6 <div class="ques_num">已解决:{{ number }}</div> 7 <button class="tip_btn" @click="tipHandle">规则</button> 8 <div class="tip" v-if="show_tip"> 9 <div class="tip_c">使用给定的4个数字(每个数字必须且只能使用一次),通过加、减、乘、除和括号运算,使最终结果等于24。</div> 10 <button class="con_c" @click="conHandle">关闭</button> 11 </div> 12 <br> 13 </div> 14 <div class="content"> 15 <div class="num"> 16 <div class="num_s" v-for="(item, index) in texts" :key="index"> 17 <button class="num_item" @click="numHandle(index)">{{ item }}</button> 18 </div> 19 </div> 20 <div class="opener"> 21 <div class="opener_i" v-for="(opener, index) in openers" :key="index"> 22 <button class="opener_item" @click="openerHandle(index)">{{ opener }}</button> 23 </div> 24 </div> 25 <div class="input"> 26 <div class="input_t">{{ str }}</div> 27 <button class="can_btn" @click="canHandle">确认</button> 28 </div> 29 </div> 30 <div class="select"> 31 <div class="sel_one"> 32 <button class="next_btn" @click="nextHandle">下一题</button> 33 <button class="clear_btn" @click="clearHandle">清空</button> 34 </div> 35 <div> 36 <button class="start_btn" @click="startHandle">开始</button> 37 </div> 38 <div class="sel_two"> 39 <button class="restart_btn" @click="renewHandle">计时</button> 40 <button class="stop_btn" @click="stopHandle">{{ btn }}</button> 41 </div> 42 43 </div> 44 </div> 45</template> 46<script> 47export default { 48 data() { 49 return { 50 time: "00:00", 51 totalTime: 0, 52 isok: true, 53 number: 0, 54 show_tip: false, 55 num: [1, 2, 3, 4, 5, 6, 7, 8, 9], 56 openers: ['+', '-', '*', '/'], 57 texts: [0, 0, 0, 0], 58 copy: [0, 0, 0, 0], 59 btn: "暂停", 60 str1: 0, 61 str2: 0, 62 sum: 0, 63 str: "", 64 open: "" 65 } 66 }, 67 68 methods: { 69 tipHandle() { 70 this.show_tip = true 71 }, 72 conHandle() { 73 this.show_tip = false 74 }, 75 renewHandle() { 76 if (!this.isok) return; 77 if (this.isok) { 78 this.totalTime++; 79 const min = Math.floor(this.totalTime / 60); 80 const sec = Math.floor(this.totalTime % 60); 81 this.time = [`${min.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`](function toString() { [native code] }); 82 } 83 setTimeout(() => this.renewHandle(), 1000); 84 }, 85 nextHandle() { 86 //this.totalTime=0; 87 let i = 4; 88 for (let j = 0; j < i; j++) { 89 this.texts[j] = Math.floor(Math.random() * (9)) + 1 90 //console.log(texts[0]) 91 } 92 93 this.sum = 0 94 this.str = "" 95 this.copy = [...this.texts] 96 //this.copy = this.texts 这是引用赋值,对texts操作也会影响到copy,这里不能使用 97 }, 98 clearHandle() { 99 this.texts = [...this.copy] 100 this.str = "" 101 this.str1 = 0 102 this.str2 = 0 103 }, 104 stopHandle() { 105 this.btn = this.isok ? "开始" : "暂停" 106 this.isok = !this.isok; 107 this.renewHandle(); 108 109 }, 110 startHandle() { 111 this.totalTime = 0 112 this.renewHandle() 113 this.nextHandle() 114 }, 115 numHandle(index) { 116 if (this.str1 == 0) 117 this.str1 = this.texts[index] 118 else 119 this.str2 = this.texts[index] 120 121 this.str = this.str + String(this.texts[index]) 122 this.texts.splice(index, 1) 123 }, 124 openerHandle(index) { 125 this.open = this.openers[index] 126 this.str = this.str + this.open 127 }, 128 canHandle() { 129 if (this.str1 > 0 && this.str1 < 10 && this.str2 > 0 && this.str2 < 10 && this.open !='') { 130 switch (this.open) { 131 case '+': 132 this.sum = this.str1 + this.str2; 133 break; 134 case '-': 135 this.sum = this.str1 - this.str2; 136 break; 137 case '*': 138 this.sum = this.str1 * this.str2; 139 break; 140 case '/': 141 this.sum = this.str1 / this.str2; 142 break; 143 } 144 145 this.texts.push(this.sum) 146 this.str1 = 0 147 this.str2 = 0 148 this.str = "" 149 if (this.texts.length == 1 && this.sum == 24) { 150 ++this.number; 151 this.nextHandle() 152 } 153 } 154 else{ 155 alert('不能计算') 156 this.clearHandle() 157 } 158 }, 159 } 160} 161</script> 162 163<style> 164body { 165 display: flex; 166 justify-content: center; 167 align-items: center; 168 background-color: rgba(186, 191, 94, 0.6); 169} 170 171.box_one { 172 height: 800px; 173 width: 850px; 174 position: relative; 175 background: linear-gradient(135deg, #c9df58, #97eae2, #80cbaa); 176 display: flex; 177 justify-content: center; 178 align-items: center; 179 flex-direction: column; 180 border: none; 181 border-radius: 15px; 182} 183 184.title { 185 top: 20px; 186 font-size: 45px; 187 font-family: "宋体"; 188} 189 190.box_two { 191 top: 30px; 192 display: flex; 193 flex-direction: row; 194 column-gap: 35px; 195 font-size: 35px; 196 font-family: "宋体"; 197} 198 199.tip_btn { 200 border-radius: 10px; 201 width: 75px; 202 height: 45px; 203 border: none; 204 background-color: rgb(235, 223, 165); 205 font-size: 20px; 206 font-family: "宋体"; 207} 208 209.tip { 210 width: 350px; 211 height: 100px; 212 border-radius: 10px; 213 background-color: rgba(238, 232, 225, 0.7); 214} 215 216.tip_c { 217 font-size: 18px; 218} 219 220.con_c { 221 position: relative; 222 width: 65px; 223 height: 45x; 224 background: linear-gradient(135deg, #c9df58, #97eae2, #80cbaa); 225 border: none; 226 border-radius: 10px; 227 right: -250px; 228 bottom: 10px; 229} 230 231.content { 232 position: relative; 233 top: 30px; 234 background-color: rgba(239, 234, 231, 0.8); 235 width: 60%; 236 height: 35%; 237 border-radius: 20px; 238 padding: 20px; 239 align-items: center; 240 justify-content: center; 241 display: flex; 242 flex-direction: column; 243} 244 245.num { 246 display: flex; 247 flex-direction: row; 248 column-gap: 30px; 249} 250 251.opener { 252 position: relative; 253 top: 20px; 254 display: flex; 255 flex-direction: row; 256 column-gap: 30px; 257} 258 259.num_s { 260 height: 30%; 261 width: 100%; 262} 263 264.num_item { 265 background: linear-gradient(135deg, #7145da, #d688c6); 266 border: none; 267 border-radius: 10px; 268 height: 70px; 269 width: 90px; 270 font-size: 25px; 271 color: #e4dede; 272 align-items: center; 273 justify-content: center; 274} 275 276.opener_i { 277 height: 30%; 278 width: 100%; 279} 280 281.opener_item { 282 display: flex; 283 flex-direction: row; 284 background: linear-gradient(135deg, #3e4163, #606c82); 285 color: #f8f4f4; 286 border: none; 287 border-radius: 10px; 288 height: 70px; 289 width: 90px; 290 font-size: 25px; 291 align-items: center; 292 justify-content: center; 293} 294 295.input { 296 position: relative; 297 top: 40px; 298 height: 15%; 299 width: 40%; 300 flex-direction: row; 301 column-gap: 20px; 302 display: flex; 303 justify-content: center; 304 align-items: center; 305} 306 307.input_t { 308 display: flex; 309 justify-content: center; 310 align-items: center; 311 width: 80%; 312 height: 35px; 313 background-color: aliceblue; 314 border-radius: 15px; 315} 316 317.can_btn { 318 border-radius: 10px; 319 position: relative; 320 right: 0; 321 border: none; 322 height: 40px; 323 background: #97eae2; 324} 325 326.select { 327 position: relative; 328 top: 60px; 329 width: 50%; 330 height: 30%; 331 background-color: rgba(218, 221, 204, 0.5); 332 display: flex; 333 flex-direction: column; 334 row-gap: 5px; 335 border-radius: 20px; 336 justify-content: center; 337 align-items: center; 338 font-size: 40px; 339 font-family: '楷体'; 340} 341 342.sel_one { 343 display: flex; 344 flex-direction: row; 345 column-gap: 80px; 346 347} 348 349.sel_two { 350 display: flex; 351 flex-direction: row; 352 column-gap: 80px; 353} 354 355.next_btn { 356 border: none; 357 width: 80px; 358 height: 55px; 359 background: linear-gradient(135deg, #c1e663, #c9df58, #d5d5b9); 360 border-radius: 15px; 361 font-size: 20px; 362 font-family: '宋体'; 363} 364 365.clear_btn { 366 width: 80px; 367 height: 55px; 368 border: none; 369 background: linear-gradient(135deg, #c1e663, #c9df58, #d5d5b9); 370 border-radius: 15px; 371 font-size: 20px; 372 font-family: '送体'; 373} 374 375.start_btn { 376 width: 60px; 377 height: 55px; 378 border: none; 379 background: linear-gradient(135deg, #e8895d, #ee9f85, #f2d8c3); 380 border-radius: 15px; 381 font-size: 20px; 382 font-family: '宋体'; 383 color: white; 384} 385 386.restart_btn { 387 width: 80px; 388 height: 55px; 389 border: none; 390 background: linear-gradient(135deg, #80cbaa, #79ac5c, #423e34); 391 border-radius: 15px; 392 font-size: 20px; 393 font-family: '宋体'; 394 color: white; 395} 396 397.stop_btn { 398 width: 80px; 399 height: 55px; 400 border: none; 401 background: linear-gradient(135deg, #80cbaa, #79ac5c, #423e34); 402 border-radius: 15px; 403 font-size: 20px; 404 font-family: '宋体'; 405 color: white; 406} 407</style>
《使用前端框架vue做一个小游戏》 是转载文章,点击查看原文。
