首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
第 7 章 处理用户交互
7.1 事件的监听与处理
7.1.1 事件监听示例
7.1.2 多事件处理
7.1.3 事件修饰符
7.2 Vue中的事件类型
7.2.1 常用的事件类型
7.2.2 按键修饰符
7.3 实战一:随鼠标移动的小球
7.4 实战二:弹球游戏
第 8 章 组件基础
8.1 关于Vue应用与组件
8.1.1 Vue应用的数据配置选项
8.1.2 定义组件
8.2 组件中数据与事件的传递
8.2.1 为组件添加外部属性
8.2.2 处理组件事件
8.2.3 在组件上使用v-model指令
8.3 自定义组件的插槽
8.3.1 组件插槽的基本用法
8.3.2 多具名插槽的用法
8.4 动态组件的简单应用
8.5 实战:开发一款小巧的开关按钮组件
第 9 章 组件进阶
9.1 组件的生命周期与高级配置
9.1.1 生命周期方法
9.1.2 应用的全局配置选项
9.1.3 组件的注册方式
9.2 组件props属性的高级用法
9.2.1 对props属性进行验证
9.2.2 props的只读性质
9.2.3 组件数据注入
9.3 组件Mixin技术
9.3.1 使用Mixin来定义组件
9.3.2 Mixin选项的合并
9.3.3 进行全局Mixin
9.4 使用自定义指令
9.4.1 认识自定义指令
9.4.2 自定义指令的参数
9.5 组件的Teleport功能
第 10 章 Vue响应性编程
10.1 响应性编程原理与在Vue中的应用
10.1.1 手动追踪变量的变化
10.1.2 Vue中的响应性对象
10.1.3 独立的响应性值Ref的应用
10.2 响应式的计算与监听
10.2.1 关于计算变量
10.2.2 监听响应式变量
10.3 组合式API的应用
10.3.1 关于setup方法
10.3.2 在setup方法中定义生命周期行为
10.4 实战:支持搜索和筛选的用户列表示例
10.4.1 常规风格的示例工程开发
10.4.2 使用组合式API重构用户列表页面
当前位置:
首页>>
技术小册>>
TypeScript和Vue从入门到精通(三)
小册名称:TypeScript和Vue从入门到精通(三)
### 7.4 实战二:弹球游戏 在前面的章节中,我们已经深入学习了TypeScript和Vue.js的基础知识,包括组件化开发、状态管理、路由配置以及Vuex等高级特性。为了将理论知识转化为实践能力,本章节将引导你通过开发一个简单的弹球游戏来巩固所学,并探索Vue与TypeScript结合在项目中的实际应用。 #### 7.4.1 项目概述 弹球游戏(Ball Bounce Game)是一款经典的休闲游戏,玩家通过控制一个挡板来反弹不断下落的球,以防止其落地。游戏界面简单,但背后涉及到了动画处理、碰撞检测、得分计算等编程概念。使用Vue.js结合TypeScript开发此游戏,不仅可以锻炼我们的前端编程能力,还能加深对Vue响应式系统、组件通信以及TypeScript类型安全的理解。 #### 7.4.2 项目搭建 首先,我们需要使用Vue CLI创建一个新的Vue项目,并配置TypeScript支持。如果你还没有安装Vue CLI,可以通过npm或yarn来安装: ```bash npm install -g @vue/cli # 或者 yarn global add @vue/cli ``` 然后,创建一个新的Vue项目,并添加TypeScript支持: ```bash vue create ball-bounce-game # 在提示时选择配置TypeScript ``` #### 7.4.3 游戏组件设计 为了保持代码的清晰和可维护性,我们将游戏拆分为几个关键组件: 1. **GameContainer**:游戏容器组件,负责整个游戏的布局和初始化。 2. **Ball**:球组件,控制球的移动、速度以及碰撞检测。 3. **Paddle**:挡板组件,用户可以通过键盘控制挡板的左右移动。 4. **ScoreBoard**:计分板组件,显示当前得分。 #### 7.4.4 实现细节 ##### 7.4.4.1 GameContainer 组件 GameContainer作为游戏的主容器,负责初始化游戏状态、渲染子组件,并处理游戏逻辑。 ```vue <template> <div class="game-container"> <Paddle ref="paddle" /> <Ball ref="ball" /> <ScoreBoard :score="score" /> </div> </template> <script lang="ts"> import { defineComponent, ref, onMounted, watch } from 'vue'; import Paddle from './Paddle.vue'; import Ball from './Ball.vue'; import ScoreBoard from './ScoreBoard.vue'; export default defineComponent({ components: { Paddle, Ball, ScoreBoard }, setup() { const ball = ref(null) as any; // TypeScript需要类型断言 const paddle = ref(null) as any; const score = ref(0); onMounted(() => { // 初始化游戏逻辑,如启动球的运动 if (ball.value && paddle.value) { ball.value.startGame(); } }); // 监听球的得分事件 watch(() => ball.value?.score, (newVal) => { score.value = newVal; }); return { ball, paddle, score }; } }); </script> <style scoped> .game-container { position: relative; width: 100%; height: 500px; background-color: #000; overflow: hidden; } </style> ``` ##### 7.4.4.2 Ball 组件 Ball组件负责球的移动、碰撞检测以及得分逻辑。 ```vue <template> <div ref="ballElement" class="ball"></div> </template> <script lang="ts"> import { defineComponent, ref, onMounted, watch, computed, nextTick } from 'vue'; interface BallProps { x: number; y: number; speedX: number; speedY: number; paddleWidth: number; paddlePosition: number; } export default defineComponent({ props: { paddleWidth: { type: Number, required: true }, paddlePosition: { type: Number, required: true } }, setup(props, { emit }) { const ballElement = ref(null) as any; const { x, y, speedX, speedY } = ref({ x: 50, y: 100, speedX: 3, speedY: 3 }); const moveBall = () => { // 更新球的位置 x.value += speedX.value; y.value += speedY.value; // 边界碰撞检测 if (y.value > 500 || y.value < 0) { speedY.value = -speedY.value; // 垂直反弹 } // 与挡板碰撞检测 if (x.value + 20 > props.paddlePosition && x.value < props.paddlePosition + props.paddleWidth) { if (y.value + 20 > 470) { // 假设挡板在底部 speedY.value = -speedY.value; if (Math.abs(x.value - (props.paddlePosition + props.paddleWidth / 2)) < 10) { // 如果球击中挡板中心,增加速度 speedX *= 1.1; } } } // 更新DOM nextTick(() => { ballElement.value.style.transform = `translate(${x.value}px, ${y.value}px)`; }); requestAnimationFrame(moveBall); }; onMounted(() => { moveBall(); }); return { ballElement, x, y }; } }); </script> <style scoped> .ball { width: 20px; height: 20px; background-color: red; position: absolute; border-radius: 50%; } </style> ``` 注意:这里的代码简化了部分逻辑,如得分和挡板控制,这些将在Paddle组件中处理。 ##### 7.4.4.3 Paddle 组件 Paddle组件负责接收键盘事件,控制挡板的左右移动。 ```vue <template> <div ref="paddleElement" class="paddle" :style="{ left: paddlePosition + 'px' }"></div> </template> <script lang="ts"> import { defineComponent, ref, onMounted, onUnmounted } from 'vue'; export default defineComponent({ setup() { const paddleElement = ref(null) as any; const paddleWidth = 100; const paddlePosition = ref(400); // 初始位置 const movePaddle = (event: KeyboardEvent) => { if (event.key === 'ArrowLeft' && paddlePosition.value > 0) { paddlePosition.value -= 10; } else if (event.key === 'ArrowRight' && paddlePosition.value < window.innerWidth - paddleWidth) { paddlePosition.value += 10; } }; onMounted(() => { window.addEventListener('keydown', movePaddle); }); onUnmounted(() => { window.removeEventListener('keydown', movePaddle); }); return { paddleElement, paddleWidth, paddlePosition }; } }); </script> <style scoped> .paddle { width: 100px; height: 20px; background-color: blue; position: absolute; bottom: 0; left: 0; } </style> ``` ##### 7.4.4.4 ScoreBoard 组件 ScoreBoard组件负责显示当前得分。 ```vue <template> <div class="score-board">{{ score }}</div> </template> <script lang="ts"> import { defineComponent, PropType } from 'vue'; export default defineComponent({ props: { score: { type: Number, required: true } } }); </script> <style scoped> .score-board { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); color: white; font-size: 24px; font-weight: bold; } </style> ``` #### 7.4.5 总结 通过本章节的
上一篇:
7.3 实战一:随鼠标移动的小球
下一篇:
第 8 章 组件基础
该分类下的相关小册推荐:
TypeScript和Vue从入门到精通(二)
VUE组件基础与实战
Vue.js从入门到精通(三)
TypeScript和Vue从入门到精通(一)
Vue原理与源码解析
移动端开发指南
TypeScript和Vue从入门到精通(五)
vue项目构建基础入门与实战
TypeScript和Vue从入门到精通(四)
Vue面试指南
Vue源码完全解析
vuejs组件实例与底层原理精讲