vue学习记录 3
近日笔记简写。
功能实现汇总
页面循环次数创建控件:制作一个11行11列的表格,用v-for实现。
<table> <tr v-for="index_y in 11" :key="index_y"> <td colspan="1" v-for="index_x in 11" :key="index_x"></td> </tr> </table>
制作一个可以点击后改变颜色的按钮:temple需要设置class和@click,script在methods里写事件,style写切换类。
<template> <div class="hello"> <button class="btn1" @click="btn1data()" :class="showmode ? 'active' : 'btn1'" > 按钮1 </button> </div> </template> <script> export default { data () { return { msg: 'Welcome to Vue.js App: Winmine', showmode: true } }, methods: { btn1data () { this.showmode = !(this.showmode) } } } </script> <style scoped> .btn1 { width: 140px; height: 40px; border: 1px solid #d9d9d9; border: 0; outline: none; } .btn1.active { background: green; } </style>
组件父传子:props
<!-- 根组件 --> <template> <div><!-- ...... --> <game-page v-if="showGame" :game-info="gameInfo"></game-page> <!-- ...... --></div> </template> <script> import GamePage from '@/components/GamePage.vue' export default { components: { GamePage }, data () { // 搁父组件参数 return { gameInfo: [8, 8, 10] } }, methods: { // 搁父组件函数 //.............. } } </script>
<!-- 子组件 --> <template> <div> <div>地雷数:{{ num }}</div> <div>地雷数:{{ gameInfo }}</div> </div> </template> <!-- 函数调用也一样,直接用名字 --> <script> export default { props: ['gameInfo'], data () { return { rows: this.gameInfo[0], cols: this.gameInfo[1], num: this.gameInfo[2] } } } </script>
组件子传父:$emit
<!-- 根组件 --> <template> <div><!-- --> <game-page @back-chose="backChose"></game-page> <!-- --></div> </template> <script> import GamePage from '@/components/GamePage.vue' export default { components: { GamePage }, data () { // 搁父组件参数 return {} }, methods: { // 搁父组件函数 backChose () { //............ } } } </script>
<!-- 子组件 --> <template> <div> <button @click="showDangers()">查看地雷</button> </div> </template> <script> export default { data () { return {} }, methods: { backPage () { this.$emit('back-chose') } } } </script>
列表绑数据:
<template> <div> <div>选择难度</div> <ul> <li v-for="(item, index) in level" :key="index" @click="handlelevel(item.value)"> {{ item.text }} </li> </ul> </div> </template> <script> export default { data () { return { level: [ { text: '简单', value: [9, 9, 10] }, { text: '困难', value: [16, 16, 50] } ] } }, methods: { handlelevel (level) { console.log('set', level) } } } </script>
assets图片资源调用:
<!-- 普通路径调用 --> <img :src="require('../assets/null.png')"/> <!-- 加参选择文件调用:${value} 为变量 --> <img :src="require(`../assets/cell${value}.png`)"/>
v-for双层循环且绑定对象,v-if / v-else-if / v-else筛条件显示:
1 <div class="board"> 2 <!-- for 行 --> 3 <div v-for="(row, rowIndex) in board" :key="rowIndex" 4 class="row"> 5 <!-- for 列--> 6 <div v-for="(cell, cellIndex) in row" :key="cellIndex" 7 :class="[{ opened: cell.opened }, `cell-${cell.value}`]" 8 @click="clickCell(rowIndex, cellIndex)"> 9 <!-- for内 v-if --> 10 <span v-if="cell.opened && cell.value !== 'mine'"> 11 <img :src="require(`../assets/cell${cell.value}.png`)"/> 12 </span> 13 <!-- for内 v-else-if --> 14 <span v-else-if="cell.opened"> 15 <img :src="require('../assets/mine.png')"/> 16 </span> 17 <!-- for内 v-else --> 18 <span v-else> 19 <img :src="require('../assets/null.png')"/> 20 </span> 21 </div> 22 <!-- for 列 结束--> 23 </div> 24 <!-- for 行 结束--> 25 </div>
data写了对象但是没写属性,没关系:
<script> export default { data () { return { board: [] } }, methods: { initGame () { for (let i = 0; i < this.rows; i++) { const row = [] for (let j = 0; j < this.cols; j++) { row.push({value: '', opened: false, flagged: false}) } this.board.push(row) // board其实是二维list // 如果只有一层for,board就是一维list } } } </script>
methods中关于随机数生成: (0~n):Math.floor(Math.random() * n)
methods中,对扫雷游戏rows*cols规格棋盘随机生成num个地雷:
getMines () { let cnt = 0 while (cnt < this.num) { const row = Math.floor(Math.random() * this.rows) const col = Math.floor(Math.random() * this.cols) if (!this.board[row][col].value) { this.board[row][col].value = 'mine' cnt++ } } }
页面警告(methods函数内): alert('You Game Over')
增加按键右键事件:
<template> <div class="cell" @contextmenu.prevent="onRightClick"> </div> </template>
<script> export default { methods: { onRightClick(event) { // TODO } } } </script>
新建项目后清空自带页面,并自建内容 教程参考网址:
https://blog.csdn.net/Tsailing666/article/details/127954443
需求目录:(非必需)
1 api 2 assets 3 components 4 icons 5 layout 6 router 7 store 8 styles 9 utils 10 views
简单的扫雷功能实现:(包括难度选择/插旗判断/点周围无雷扩散格子)
涉及目录及文件:其他的都不用动
<<src
--|<<assets
--|--|<<cell0.png......<<cell8.png
--|--|<<flag.png
--|--|<<mine.png
--|--|<<null.png
--|<<components
--|--|<<GamePage.vue
--|--|<<SelectLevel.vue
--|<<App.vue
App.vue:
1 <!-- 根组件 --> 2 <template> 3 <div id="app"> 4 helloworld-vue 5 <!-- 游戏盘 v-if判断showGame,是的话就展示 --> 6 <game-page 7 v-if="showGame" 8 :game-info="gameInfo" 9 @back-chose="backChose"></game-page> 10 <!-- 难度选择框,带参函数但是此处不需要写参 --> 11 <select-level 12 v-else 13 @chose-level="choseLevel"></select-level> 14 </div> 15 </template> 16 17 <script> 18 // import 子组件 from 路径 19 import SelectLevel from '@/components/SelectLevel.vue' 20 import GamePage from '@/components/GamePage.vue' 21 export default { 22 name: 'App', 23 // 增加子组件 24 components: { 25 GamePage, 26 SelectLevel 27 }, 28 // 搁本组件参数 29 data () { 30 return { 31 showGame: false, 32 gameInfo: [8, 8, 10] 33 } 34 }, 35 // 搁本组件函数 36 methods: { 37 choseLevel (level) { 38 this.gameInfo = level 39 this.showGame = true 40 console.log('get', level) 41 }, 42 backChose () { 43 this.showGame = false 44 } 45 } 46 } 47 </script> 48 49 <style> 50 #app { 51 font-family: 'Avenir', Helvetica, Arial, sans-serif; 52 -webkit-font-smoothing: antialiased; 53 -moz-osx-font-smoothing: grayscale; 54 text-align: center; 55 color: #2c3e50; 56 margin-top: 60px; 57 } 58 </style>
SelectLevel.vue
1 <!-- 选择难度组件 --> 2 <template> 3 <div> 4 <div>选择难度</div> 5 <ul> 6 <li 7 v-for="(item, index) in level" :key="index" 8 @click="handlelevel(item.value)"> 9 {{ item.text }} 10 </li> 11 </ul> 12 </div> 13 </template> 14 15 <script> 16 export default { 17 name: 'index', 18 data () { 19 return { 20 level: [ 21 { 22 text: '简单', 23 value: [9, 9, 10] 24 }, { 25 text: '困难', 26 value: [16, 16, 50] 27 } 28 ] 29 } 30 }, 31 methods: { 32 handlelevel (level) { 33 this.$emit('chose-level', level) 34 console.log('set', level) 35 } 36 } 37 } 38 </script> 39 40 <style scoped> 41 ul { 42 list-style-type: none; 43 padding: 0; 44 } 45 li { 46 display: inline-block; 47 margin: 20px; 48 border-width: 0.1cm; 49 border-color: rgb(15, 75, 15); 50 background: rgb(147, 234, 147); 51 width: 1.8cm; 52 } 53 </style>
GamePage.vue
1 <!-- 游戏界面组件 --> 2 <template> 3 <div> 4 <button @click="backPage()">返回主页</button> 5 <button @click="showDangers()">查看地雷</button> 6 <button @click="resetGame()">重新开始</button> 7 <div>地雷数:{{ num }}</div> 8 <div class="board"> 9 <div 10 v-for="(row, rowIndex) in board" :key="rowIndex" 11 class="row"> 12 <div 13 v-for="(cell, cellIndex) in row" :key="cellIndex" 14 :class="[{ opened: cell.opened }, `cell-${cell.value}`]" 15 @click="clickCell(rowIndex, cellIndex)" 16 @contextmenu.prevent="onRightClick(rowIndex, cellIndex)"> 17 <span v-if="cell.flagged"> 18 <img :src="require('../assets/flag.png')"/> 19 </span> 20 <span v-else-if="cell.opened && cell.value !== 'mine'"> 21 <img :src="require(`../assets/cell${cell.value}.png`)"/> 22 </span> 23 <span v-else-if="cell.opened"> 24 <img :src="require('../assets/mine.png')"/> 25 </span> 26 <span v-else> 27 <img :src="require('../assets/null.png')"/> 28 </span> 29 </div> 30 </div> 31 </div> 32 </div> 33 </template> 34 35 <script> 36 export default { 37 props: ['gameInfo'], 38 data () { 39 return { 40 rows: this.gameInfo[0], 41 cols: this.gameInfo[1], 42 num: this.gameInfo[2], 43 board: [], 44 gameover: false 45 } 46 }, 47 created () { 48 this.initGame() 49 }, 50 methods: { 51 onRightClick (row, col) { 52 console.log('onRightClick') 53 // Event.preventDefault() 54 this.board[row][col].flagged = !this.board[row][col].flagged 55 this.checkWin() 56 }, 57 initGame () { 58 for (let i = 0; i < this.rows; i++) { 59 const row = [] 60 for (let j = 0; j < this.cols; j++) { 61 row.push({value: '', opened: false, flagged: false}) 62 } 63 this.board.push(row) 64 } 65 this.getMines() 66 this.calculateMines() 67 }, 68 getMines () { 69 let cnt = 0 70 while (cnt < this.num) { 71 const row = Math.floor(Math.random() * this.rows) 72 const col = Math.floor(Math.random() * this.cols) 73 if (!this.board[row][col].value) { 74 this.board[row][col].value = 'mine' 75 cnt++ 76 } 77 } 78 }, 79 calculateMines () { 80 for (let i = 0; i < this.rows; i++) { 81 for (let j = 0; j < this.cols; j++) { 82 if (this.board[i][j].value !== 'mine') { 83 let cnt = 0 84 // 上3 85 if (i > 0 && j > 0 && this.board[i - 1][j - 1].value === 'mine') cnt++ 86 if (i > 0 && this.board[i - 1][j].value === 'mine') cnt++ 87 if (i > 0 && j < this.cols - 1 && this.board[i - 1][j + 1].value === 'mine') cnt++ 88 // 中2 89 if (j > 0 && this.board[i][j - 1].value === 'mine') cnt++ 90 if (j < this.cols - 1 && this.board[i][j + 1].value === 'mine') cnt++ 91 // 下3 92 if (i < this.rows - 1 && j > 0 && this.board[i + 1][j - 1].value === 'mine') cnt++ 93 if (i < this.rows - 1 && this.board[i + 1][j].value === 'mine') cnt++ 94 if (i < this.rows - 1 && j < this.cols - 1 && this.board[i + 1][j + 1].value === 'mine') cnt++ 95 // end 96 this.board[i][j].value = cnt 97 } 98 } 99 } 100 }, 101 clickCell (row, col) { 102 if (this.gameover) return 103 const cell = this.board[row][col] 104 if (cell.opened || cell.flagged) return 105 cell.opened = true 106 if (cell.value === 'mine') { 107 this.gameover = true 108 this.showDangers() 109 } else if (cell.value === 0) { 110 this.openCell(row, col) 111 } 112 if (this.checkWin()) { 113 this.gameover = true 114 } 115 }, 116 openCell (row, col) { 117 if (row > 0 && col > 0) { 118 this.clickCell(row - 1, col - 1) 119 } 120 if (row > 0) { 121 this.clickCell(row - 1, col) 122 } 123 if (row > 0 && col < this.cols - 1) { 124 this.clickCell(row - 1, col + 1) 125 } 126 if (col > 0) { 127 this.clickCell(row, col - 1) 128 } 129 if (col < this.cols - 1) { 130 this.clickCell(row, col + 1) 131 } 132 if (row < this.rows - 1 && col > 0) { 133 this.clickCell(row + 1, col - 1) 134 } 135 if (row < this.rows - 1) { 136 this.clickCell(row + 1, col) 137 } 138 if (row < this.rows - 1 && col < this.cols - 1) { 139 this.clickCell(row + 1, col + 1) 140 } 141 }, 142 checkWin () { 143 let clickcnt = 0 144 for (let i = 0; i < this.rows; i++) { 145 for (let j = 0; j < this.cols; j++) { 146 // 点开格子且格子有雷 147 if (this.board[i][j].opened) { 148 clickcnt++ 149 if (this.board[i][j].value === 'mine') { 150 alert('You Game Over') 151 return false 152 } 153 } 154 // 镖旗但没雷 155 if (this.board[i][j].flagged) { 156 clickcnt++ 157 if (this.board[i][j].value !== 'mine') { 158 alert('You Game Over') 159 return false 160 } 161 } 162 } 163 } 164 if (clickcnt === this.rows * this.cols) { 165 // 所有格子都点过且没踩雷 166 alert('You Win! Good job!') 167 return true 168 } 169 return false 170 }, 171 resetGame () { 172 this.board = [] 173 this.gameover = false 174 this.initGame() 175 }, 176 showDangers () { 177 for (let i = 0; i < this.rows; i++) { 178 for (let j = 0; j < this.cols; j++) { 179 this.board[i][j].opened = true 180 } 181 } 182 }, 183 backPage () { 184 this.$emit('back-chose') 185 } 186 } 187 } 188 </script> 189 190 <style scoped> 191 button { 192 background-color: lightgreen; 193 color: white; 194 border-color: white; 195 margin: 0.5cm; 196 width: 3cm; 197 height: 1.2cm; 198 } 199 .board { 200 background-color: lightgreen; 201 display: inline-block; 202 border: 10px solid lightgreen; 203 margin: 10px; 204 } 205 .row { 206 display: flex; 207 } 208 img { 209 width: 30px; 210 height: 30px; 211 } 212 </style>
参考的资料比较多,甚至有问GPT机器人解决的。机器人也有点坑,比如右键事件给了我一个写了会报错的函数。现在算是入门了。
接下来几天研究线程和数据库。打算写个简单的书籍管理系统。
浙公网安备 33010602011771号