链接地址:
游戏开发基于vue开发的扫雷小游戏系统源码.zip资源-CSDN文库https://download.csdn.net/download/2402_83140078/89323534
前言
以前一直使用 jquery 开发,到现在,接触 vue 也有一年多时间了,期间不少朋友都问过我,从 jquery 转到 vue 容易吗? 怎么快速入门? 终于,最近比较闲,就准备写一点东西,希望能够对有这方面想法的朋友提供一丁点的帮助。
在这些文章中,并没有囊括 Vue 的所有内容,甚至没有大部分内容,可以说仅仅是冰山一角,权作抛砖引玉吧。
这个系列的文章,适用于已经熟悉前端开发,但未接触过 VUE 这样的架构的朋友,当然,了解或者熟悉 nodejs 开发会更好。如果你不懂 js,甚至没有接触过,这些可能就不适合你了。同样,这些文章仅用于入门,不适用于深入学习。
大纲
- 搭建环境
- NodeJS
- 了解 npm 命令
- Vue-CLI
- 开发工具 vscode
- 开发插件 vue-devtools
- 创建第一个 Vue 应用
- 创建项目
- 目录结构说明
- 了解组件
- 什么是组件?存在的意义
- 组件的结构以及使用
- 编写第一个组件 面板 Board.vue
- 准备数据结构
- 构建布局/样式
- 生成扫雷数据
- 编写第二个组件 雷区 Square.vue
- Square.vue
- 翻开雷区
- 插旗标记
- 游戏统计以及结果
- 组件的事件传递
搭建 Vue 开发环境
Vue 的开发利用了 NodeJS 的便利性,通过 npm
可以获取很多第三方的代码,同时,npm
也是开发时的命令工具入口。
注:以后将
NodeJS
均称作node
安装 node
去搜索 nodejs
,然后下载系统版本对应的安装包,然后安装。
npm 基本用法
npm
即 node Package Manager,其实这是一个 javascript 包的管理工具,并不限用 node 的包。
在 node 安装成功后,会自动安装上 npm ,此时的 npm 可能不是最新的版本,你可以通过命令
npm i npm@latest -g
来安装最新的 npm
npm init <project>
创建一个名为project
的 node 项目npm install <package>[@<version>] [--save|--save-dev]
向当前项目安装包package
install
表示安装命令,可以缩写成i
@<version>
是要安装的版本号,留空表示安装最新版本--save
是指要安装的包记录写入 package.json 文件中的依赖节点(dependencies)--save-dev
功能同--save
,但会将记录写入开发依赖节点(devDependencies),表示此包是开发时使用的,并不是产品上使用的- 平时在安装包时,若没有特别需要,只需要
npm i <package>
就可以了
npm run <command>
执行package.json
中scripts
节点下的命令- 在使用 Vue 的时候,会常常用到
npm run dev
或npm run serve
- 在使用 Vue 的时候,会常常用到
当然,也可以使用
yarn
作为包管理工具(这也是 Vue 官方推荐的工具),其用法此处略过
安装 Vue-CLI
Vue cli 是 Vue 官方提供的一整套脚手架,用于创建和管理 Vue 项目。通过以下命令来安装
npm i @vue/cli -g
安装后,可以通过以下命令测试安装结果
vue --version
此时应该会显示当前的 vue cli 版本号。
安装开发工具 VSCODE
本质上,Vue 并不挑开发工具,即使是轻量如 nodepad++ 也能胜任。但是,使用 IDE 能得到极大的便利,包括静态错误检查以及智能提示。、
WebStorm 本应该是首选的 IDE,不过是收费的,而且安装包也很大,相比之下 VS Code 就更加平民化了。
好吧,去搜索 vs code ,然后安装吧。安装好后,还需要安装 Vetur
插件以支持 Vue 语法,以及 ESLint
插件,以支持静态检查。
代码格式化快捷键:
Shift+Alt+F
,后面会用到的
开发插件 vue-devtools
Vue 提供了浏览器上的开发插件,用于审查 Vue 的组件,数据,事件以及性能等。
目前此插件支持 Chrome, Firefox, Electron.
- 安装方法一: 上 github 搜索
vue-devtools
, 自动通过源码编译。- 使用源码编译时,先移除 package.json 中的测试相关项,这样能避免编译失败。
- 移除
release
项中的npm run test
命令 - 移除 所有
test
开头的命令 - 移除
devDependencies
节点下的依赖包cypress
- 移除
- 生成插件,执行命令
npm run build
- 使用源码编译时,先移除 package.json 中的测试相关项,这样能避免编译失败。
- 安装方法二: 上应用商店搜索安装
创建第一个 Vue 应用
上一节已经搭建好了基础环境,现在就可以开始干了。
创建项目
创建项目时,不需要特意去创建一个空的目录,vue-cli 会自动创建新目录作为项目目录(与项目名称相同)
执行命令创建项目 mine-sweeper
vue create mine-sweeper
创建过程中,会有一些选项,此时需要选择:
此时选择 default (babel, eslint)
,直接按 回车 即可。
此选项表示使用 babel
处理 ES6 以及 ES-next 等新功能,同时使用 eslint
执行代码检查。
注: 使用默认选仅为个人喜好,有兴趣也可以看看手动配置项
选择后会自动使用 yarn
开始安装依赖的插件。
当然,也可以选择新的 UI 方式创建 (我还没有使用过)
vue ui
安装好后,执行命令
cd mine-sweeper
yarn serve
便可以启动项目了
此时,到浏览器打开地址 http://localhost:8080/ 便能看到 HelloWord 界面了。
目录结构说明
- .git git 仓库目录
- node_modules node 包存放目录
- public 不经过编译的静态文件存放目录
- favicon.ico
- index.html 入口html文件
- src 源码目录 (也就是我们的工作目录)
- assets 需要被编译的静态文件存放目录,比如 图片 样式 脚本
- components 组件放到此目录下
- App.vue 入口组件,被 main.js 调用
- main.js 编译入口文件
- .gitignore
- babel.config.js babel 配置文件
- package.json 项目配置文件,提供给npm使用的命令,以及项目依赖存放
- README.md
- yarn.lock
为了方便后期调试,可以编辑 package.json 文件的 eslintConfig.rules
节点,添加以下内容以允许 console
和 debugger
语句:
"rules": {
"no-console": "off",
"no-debugger": "off"
}
组件
组件的结构
组件一般包含以下几部分
- 模板声明
- 组件声明
- 样式
<template>
// 你的html写在这里
</template>
<script>
export default {
name: 'ComponentName'
// ...你的组件声明写在这里
}
</script>
<style scoped>
// 你的组件内样式写在这里
</style>
<style>
// 你的全局样式写在这里
</style>
模板声明
模板是一种与 html 相同的写法的片段,用于描述文档结构。
<template>
<div>
内容
</div>
</template>
模板必需使用 template
标签为根,并且根只能拥有一个直接子元素(不限标签类型),比如:
<template>
<div>
内容1
</div>
<div>内容2</div>
</template>
这样的写法是有问题的。
模板中可以使用所有的 html 标签,也可以引用其它的组件:
<template>
<div>
<custom-component />
</div>
</template>
标签上也可以如原生的 html 一样,写属性,事件,样式,类等。
<template>
<div style="color: red;" class="class-name">
内容
</div>
</template>
组件声明
组件的声明是通过 js 实现的,需要注意的是,在 Vue 中,默认使用了 ES6 的语法,特别是其模块的导入导出。
ES6 模块的导入导出
将函数作为模块导出
haha.js
function haha() {
console.log('message from haha')
}
function hehe() {
console.log('message from haha')
}
export default haha
export { hehe }
这里使用了两种导出方式,一个默认的导出 haha
,另一个具名(没有研究过到底叫啥名,自己编的名字)的导出 hehe
在其它位置导入此模块
hehe.js
import haha from './relativePath/to/haha.js'
import { hehe } from './relativePath/to/haha.js'
haha() // 输出: message from haha
hehe() // 输出: message from hehe
注意,两种导出方式对应的导入也是不同的
好吧,再回到组件的声明。
Vue 的组件声明,就使用了默认导出的方式 export default {}
。
export default {
name: '组件名称',
// 声明此组件的属性(由父组件调用时传入),可以理解为函数的参数
props: {
// 属性名称
propName: {
// 属性的类型,多个类型时,使用数组: [String, Number]
type: String,
default: '默认值',
// 属性是否是必需的
required: false
}
// 更多的属性
},
// 引用的组件集合
components: {},
// 混入列表 [1]
mixins: [],
// 过滤器,提供给组件模板使用的管道过滤器,用于对数据的简单处理 [2]
filters: {},
// 拥有的数据,数据始终应该使用 return {} 的方式提供,以避免组件复用导致数据被共享
data() {
return {
data1: 1
}
},
// 方法集合,这些方法可以在组件内通过 this 访问,也能在模板内直接访问
methods: {},
// 组件的计算属性 [3]
computed: {
// 一个示例,用于计算 data1 的平方
hehe() {
return this.data1 ** 2
}
},
// 监视数据变化的集合,当指定的数据变化时,此处的方法会被调用
watch: {
// 监视数据 data1,在此方法内,可以实现在 data1 变化时执行代码
data1(newValue) {}
},
// 生命周期钩子: 组件创建后调用,此时组件还没挂载到 DOM 树上
created() {},
// 生命周期钩子: 组件挂载到 DOM 树上后调用,一般在这里面执行一些初始化代码
mounted() {},
// 生命周期钩子: 组件更新后调用,要注意的是,不能在这个组件内执行会更新组件的操作,否则可能会出现死循环 [4]
updated() {},
// 生命周期钩子: 组件销毁前调用,这里一般执行一些回收操作,如:数据重置,移除事件绑定,取消 setTimeout 或 setInterval 等
beforeDestroy() {}
}
[1] 混入为 Vue 中组件重用的一种方式,旨在多个组件中共用相同的声明,类似面向对象中的接口或虚类
[2] 过滤器类似数据格式化函数,在使用时,类似 linux shell 中的管道用法
[3] 计算属性用于执行自动计算,当其中使用到的数变量发生变化时,会自动重新计算其值。在使用计算属性时,需要当作一个属性,而不是一个函数,如:
this.hehe
而不是this.hehe()
。计算属性应该始终返回一个值
[4] 也不是绝对不可以执行更新代码,但是必须要有条件判断,以终止执行
这里并没有把全部结构都列出来,若有需要请移步官方文档
在模板中使用数据与逻辑
<template>
<div>
<ul>
<li v-for="item in data" :key="item">{{item}}</li>
</ul>
<div v-show="visible" @click="onClick">点击后隐藏这个元素</div>
</div>
</template>
<script>
export default {
name: 'Tt',
data(){
return {
visible: true,
data: ['hehe', 'haha', 'hihi', 'hoho]
}
},
methods: {
onClick(e) {
this.visible = false
}
}
}
</script>
解释一下上面的代码吧
v-for
这是用来搞循环的,可以遍历data
中的每一项item
:key
这是 Vue 中对循环的约束,要求循环必须设置一个唯一的key
值。另外,这个写法是v-bind:key
的简写,表示给属性key
绑定变量item
。所有的属性(组件属性,以及 html 属性均可使用此写法),如:<div :style="styleObject"></div>
{{item}}
这是模板取值的表达式,此时item
的值会被填充到li
元素中v-show
控制元素的显示/隐藏(通过设置样式display
实现);另一种相似的写法为v-if
,不同之处在于,v-if
为false
时是将元素从 DOM 树移除,而v-show
为false
时是设置display: none
@click="onClick"
为元素绑定点击事件onClick
,这是v-on:click
的简写,所有事件都能使用这样的方式来简写,比如:@mouseover
,@keydown
,自定义事件也如此- 在
onClick
方法中,有这么一句this.visible = false
,这里的this
表示的是当前的组件实例,可以通过this
访问组件的所有数据
样式
组件内样式 (含作用域),仅对当前组件生效
<style scoped>
div {
color: red;
}
</style>
这个样式将组件内的所有 div
的文字设置为 red
全局样式,对项目内所有元素生效
<style>
div {
color: red;
}
</style>
这个样式将项目内的所有 div
的文字设置为 red
也还支持导入外部样式
<style>
import "./external.css"
</style>
预编译的Less/Sass
也是支持的
<style lang="less" scoped>
div {
color: red;
> span {
color: black;
}
}
</style>
接下来的扫雷项目就会使用 less
编写样式。
组件的引用
首先,有这么一个组件 Sample.vue
<template>
<div>{{textContent}}</div>
</template>
<script>
export default {
name: 'Sample',
props: {
textContent: {
type: String
}
}
}
</script>
此组件的声明中,包含一个名叫 textContent
的属性,通过另一个组件去引用组件 Sample.vue (引用时可以通过属性指定 textContent
的值)
<template>
<div>
<sample-component :text-content="text" />
</div>
</template>
<script>
// 导入组件模块 Sample
import Sample from './Sample.vue'
export default {
name: 'Sample',
components: {
// 将组件 Sample 重命名为 SampleComponent
SampleComponent: Sample
},
data() {
return {
text: '文本1'
}
},
mounted() {
// 5秒后改变 text 的值,此时组件 Sample.vue 中的显示应该同步变化
setTimeout(() => {
// 对 text 赋值会导致界面更新,因为数据的变化被监听了
this.text = '改变后的文本'
}, 5000)
}
}
</script>
注意: 在命名组件时,一般使用 帕斯卡命名法(Pascal) ,在引入组件时,可以保留原组件名称,也可以指定新的名称,如:
export default {
component: {
// 保留原名称
Sample: Sample,
// 指定新名称
SampleComponent: Sample
}
}
按 W3C 标准,组件标签应该始终为小写,多个词时使用短横线 -
分隔(同样地,此规则也适用于属性名称),如:
<template>
<div>
<sample :text-content="text" />
<sample-component :text-content="text" />
</div>
</template>
全局引用
如果一个组件需要大范围地使用,那么像前面这样每次都引用就是一个笨办法了。Vue 提供了全局的组件注册
import Vue from 'vue'
import Sample from './components/Sample.vue'
Vue.component(Sample.name, Sample)
这样就能在项目的任意组件内使用 sample
组件了
这些代码一般会写在 main.js 中
编写第一个组件 面板
我们要开始写扫雷游戏了,此时需要删掉自动创建的一些文件,加上我们自己创建的新文件。
在这之前,可以看看 src/App.vue 以及 src/components/HelloWord.vue ,结合前一节说到的组件结构和用法,加深一些了解。
好了,开始吧,先使用 vs code 打开项目目录吧。
不要忘记通过命令
npm run serve
启动服务器
一些准备工作
到 src/components 目录创建文件 Board.vue,并填上以下代码
<template>
<div class="board"></div>
</template>
<script>
export default {
name: 'Board'
}
</script>
此时,创建了一个名叫 Board
的单文件 Vue 组件。
board,表示扫雷游戏的整个区域。
打开文件 src/App.vue,长这样的,将原来的 HelloWord.vue
组件的引用,替换成 Board.vue
的引用
<template>
<div id="app">
<board />
</div>
</template>
<script>
import Board from './components/Board.vue'
export default {
name: 'app',
components: {
Board
}
}
</script>
后面,我们整个游戏的开发都会在 Board.vue 组件中进行。
准备数据结构
首先定义一下数据结构,扫雷的行列数据,最简单就是使用二维数组来存放了,所以?那就创建一个二维数组 data
来存放吧。第一维表示雷区的行,第二维表示雷区的列就行了。
然后,一般的扫雷游戏都有个难度等级吧,我们就用 level
来表示好了,这是一个数值,值越大表示难度越大,设置个默认难度为 1
。
默认难度为 1 了,那么再默认一个雷的数量 mineCount
吧,就设置为 9 好了
再想想,还需要定义雷区的尺寸,也就是需要几行几列 size
(使行列数相同),就都设置为 9 吧
于是,得到了下面的组件数据声明:
export default {
data() {
return {
// 使用 data 作为扫雷的数据存储
data: [],
level: 1,
mineCount: 9,
size: 9
}
}
构建布局/样式
既然是扫雷游戏,那么总得有个区域吧,看起来每个雷区都是一个格子,这样的布局,不正是表格擅长的吗?
Board.vue 模板如下
<template>
<div class="board">
<table>
<tr v-for="i in size" :key="i">
<td v-for="j in size" :key="j">
{{i}}-{{j}}
</td>
</tr>
</table>
</div>
</template>
在此,使用 {{i}}-{{j}}
将行和列的值都给显示在了界面上。
不晓得你有没有注意到,
size
是个数值,在使用i in size
这样的写法时,得到的i
是从1
开始的,其结果也包含了size
的最大值9
保存后,界面会自动更新,显示如图
此时会发现,生成的表格没有边框,很难分清单元格的边界在哪里。所以,写点样式吧
<style scoped>
table {
border: 1px solid #aaaaaa;
border-collapse: collapse;
}
td {
border: 1px solid #aaaaaa;
padding: 5px;
}
</style>
显示效果如下
生成扫雷数据
生成扫雷数据的详细算法以及过程参见源码 src/component/Board.vue 中的方法
生成后的数据,被填充到了 data
中,现在,改造一下模板,使其能直接显示这些数据
<template>
<div class="board">
<table>
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td v-for="cell in row" :key="cell.col">
<span v-if="cell.mine">雷</span>
<span v-else>{{cell.count}}</span>
</td>
</tr>
</table>
</div>
</template>
显示效果如下
编写第二个组件 雷区
上一节已经画出了雷区,并且按位置放置好了雷,那么这一节,就要开始交互处理了。
但是,细细一想,在扫雷游戏中,每个雷区都会有遮罩(mask)、雷、旗、问号等显示,并且需要处理鼠标的左/右键的点击事件,相对来说,这算一个比较复杂的功能了。既然如此,就新写一个组件 Square.vue
吧。
Square.vue
Square.vue
<template>
<div class="square" :class="computedClass" @click="onClick">
<span class="text" v-if="clipped && square.mine">雷</span>
<span class="text" v-if="clipped && !square.mine">{{square.count}}</span>
</div>
</template>
<script>
export default {
name: "Square",
props: {
data: {
type: Object,
required: true
}
},
data() {
return {
// 标记此区是否已经被翻开
clipped: false
};
},
computed: {
// 自动计算样式
computedClass() {
return {
clipped: this.clipped
};
},
square() {
return this.data || {};
}
},
methods: {
onClick() {
this.clipped = true;
}
}
};
</script>
<style lang="less" scoped>
.square {
display: block;
height: 30px;
line-height: 30px;
width: 30px;
text-align: center;
background-color: burlywood;
/* 设置鼠标动作交互 */
&:hover {
background-color: lightblue;
}
}
.clipped,
.clipped:hover {
background-color: #ffffff;
}
</style>
此时,我使用了
Less
样式,需要先安装Less
支持yarn add less less-loader -D
,对应的 npm 命令为npm install less less-loader --save-dev
效果如下
现在来说明一下此组件中用到的东西:
- 设置了一个名为
data
的属性(prop),以接收从父组件Board
传过来的雷区数据。 - 设置数据
clipped
用来标记雷区是否已经翻开 - 计算属性
computedClass
用于在clipped
变化时,自动切换样式类clipped
- 计算属性
square
用于获取属性数据data
,并在其为空时使用一个空对象代替 - 方法
onClick
接收此组件被点击的事件 :class="computedClass" @click="onClick"
分别设置样式clipped
和绑定事件onClick
- 使用了
v-if
语法,在不同的条件下显示不同的内容 {{square.count}}
输出文本到界面上
在 Board.vue 中引用:
<template>
<div class="board">
<table>
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td v-for="cell in row" :key="cell.col">
<square :data="cell" />
</td>
</tr>
</table>
</div>
</template>
<script>
import Square from './Square'
export default {
// 此处省略了之前已经写好的代码
components: { Square }
}
</script>
到现在,就有了简单的鼠标交互了,此时点击雷区就能翻开指定块了。
插旗标记
回想一下扫雷这个游戏,还需要通过鼠标右键来将某个区标记为雷(插旗),所以我们需要再给组件加上鼠标的右键事件,此时,就可以对组件进行一些改造使其能同时响应鼠标的左右键事件,模板如下:
Square.vue
<template>
<div
class="square"
:class="computedClass"
@click.left="onLeftClick"
@click.right.prevent="onRightClick"
>
<span class="text" v-if="clipped && square.mine">雷</span>
<span class="text" v-if="clipped && !square.mine">{{countText}}</span>
</div>
</template>
<script>
// 省略了已经写好的部分
export default {
data() {
return {
// 标记是否已经插上了旗
flagged: false
};
},
computed: {
countText() {
return this.data.count ? this.data.count : "";
}
},
methods: {
onLeftClick() {
if (this.clipped || this.flagged) {
return;
}
this.clipped = true;
},
onRightClick() {
this.flagged = !this.flagged;
}
}
};
</script>
<style lang="less" scoped>
.flagged {
&:after {
content: "旗";
background-color: red;
color: white;
padding: 1px 3px;
font-size: 12px;
}
}
</style>
效果如图
继续解释一下新增加的部分:
@click.left
和@click.right.prevent
分别绑定鼠标的左/右键点击事件,left
、right
以及prevent
都是 Vue 提供了事件修饰符, 其中的prevent
即e.preventDefault()
flagged
新添加的数据,用于标记雷区是否使用旗标记countText
这个计算属性,用于在周围的雷数量为0
时,在界面上显示为空白
到此,扫雷的基本功能就完成了。
游戏统计以及结果
前一节完成了扫雷的基本功能:翻开雷区以及标记为雷。在这一节,就到获取游戏结果的时候了。
有个问题,我们之前的翻开雷区以及标记为雷都是在 Square
组件中实现的,但是游戏结果需要 Board
组件来统计,咋整呢? 这时候就需要用到事件传递了。
组件的事件传递
在 Vue 中,父子组件中经常会传递事件;在此,也仅仅会涉及到父组件接收子组件传递的事件。
若欲了解更多事件相关信息,请查阅文档的事件以及事件总线
子组件通过 this.$emit('event-name', payload, ...)
向父组件发事件,父组件通过在调用子组件时的 @event-name="eventHandler"
来接收并处理事件。
其中,event-name
是事件的名称,payload
是事件的负载(可以是任何类型的数据), $emit
方法在事件名后,可以传递多个参数,此时,在 eventHandler
函数上会接收到相同数量的参数。
所以,对 Square
组件进行一些改动,以将翻开与标雷事件传递给 Board
组件:
发出事件
Square.vue
export default {methods: {
onLeftClick() {
if (this.clipped || this.marked) {
return;
}
this.clipped = true;
if (this.data.mine) {
// 当前是雷时,触发爆炸事件
this.$emit("exploded");
} else {
// 当前不是雷时触发翻开事件
this.$emit("clipped");
}
},
onRightClick() {
// 切换插旗
this.marked = !this.marked;
this.$emit("marked", this.marked);
}
}
}
此时,一共触发了三个事件:
exploded
当翻开雷区时遇到雷触发clipped
当翻开雷区时未遇到雷触发marked
当插上旗后触发
接收事件
Board.vue
<template>
<div class="board">
<div>雷数量: {{mineCount}}, 已标记: {{markCount}},剩下: {{mineCount - markCount}}</div>
<table>
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td v-for="cell in row" :key="cell.col">
<square :data="cell" @clipped="onClipped" @exploded="onExploded" @marked="onMarked" />
</td>
</tr>
</table>
<div class="result" v-if="result">{{result}}</div>
</div>
</template>
<script>
// 省略已经写好的部分
export default {
data() {
return {
// 标雷数量
markCount: 0,
// 翻开数量
clipCount: 0,
// 游戏结果
result: null
};
},
watch: {
remainSquares(v) {
if (v === 0) {
this.result = "通关";
}
}
},
computed: {
remainSquares() {
return this.size ** 2 - this.markCount - this.clipCount;
}
},
methods: {
onClipped() {
this.clipCount++;
},
onExploded() {
this.result = "背时,搞爆了";
},
onMarked(marked) {
if (marked) {
this.markCount++;
} else {
this.markCount--;
}
}
}
};
</script>
在 Board
组件中,接收了三个事件 @clipped="onClipped" @exploded="onExploded" @marked="onMarked"
。另外添加了一个 div.result
用于显示游戏结果。
在游戏面板上方,添加了雷数量统计信息的展示。
新增加了一个计算属性 remainSquares
,用于计算剩下未翻开并且未插旗的雷区,当此值为0时,表示游戏通关。 this.size ** 2
表示雷区总数量。
另外,新增了一个监视器 remainSquares
,以监视其值的变化,在变化时,判断游戏是否通关。
结果来源:
- 当翻开雷时,会触发
exploded
事件,此时会设置result
的值,此时为游戏失败 - 当已经翻开和标记块之和等于总数时,,此时为游戏通过
总结
回顾这个小游戏的开发,已经介绍了以下内容:
- 使用 Vue cli 创建项目
- Vue 组件的结构
- Vue 模板以及语法
- Vue 事件传递
- Vue 计算属性
- Vue 监视器
而 Vue 远不只是如此,还有很多有意思的东西,等你去玩