一、前言:为啥选“电影购票”练手?
兄弟们,学Vue如果光啃理论不实战,就像背了菜谱却从不炒菜——最后只能饿肚子!而“电影购票APP”简直是练手神器:它囊括了列表展示、动态路由、状态管理等核心场景,而且最终效果酷炫,能直接塞进简历唬人(划掉)展示实力。
今天,咱就用Vue这个“乐高工具箱”,一步步搭出APP的页面组件和路由系统。放心,我不甩官方文档那种天书,而是用你隔壁室友都能懂的“人话”,附上每段代码的吐槽式解析。最终代码打包放文末,复制粘贴就能跑起来!
二、项目准备:先给代码化个妆
在折腾组件前,得先让项目“能跑”。用Vue CLI快速初始化(没装的自觉npm install -g @vue/cli面壁):
vue create movie-ticket-app
cd movie-ticket-app
npm install
接着安装路由库(毕竟没路由的APP就像没导航的出租车):
npm install vue-router
三、组件设计:把页面拆成“乐高块”
一个购票APP的核心页面就四个:首页、电影详情、选座页、订单页。每个页面对应一个Vue组件,咱们挨个盘它们!
1. 首页组件(Home.vue):海报墙和搜索框
首页负责展示热映电影,用户点击海报跳转到详情。代码像这样:
<template>
<div class="home">
<h1>爆米花已备好,选部电影吧!🍿</h1>
<div class="movie-list">
<div
v-for="movie in movies"
:key="movie.id"
class="movie-card"
@click="goToDetail(movie.id)"
>
<img :src="movie.poster" alt="海报">
<h3>{{ movie.title }}</h3>
<p>评分:{{ movie.rating }}</p>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
movies: [
{
id: 1,
title: "流浪地球3",
rating: 9.5,
poster: "/images/earth.jpg"
},
// ...其他电影数据
]
}
},
methods: {
goToDetail(id) {
this.$router.push(`/detail/${id}`) // 路由跳转细节后面聊
}
}
}
</script>
吐槽点解析:
v-for循环渲染海报,比复制粘贴香多了;@click绑定点击事件,注意这里用到了路由跳转,后面会细说路由配置的“坑”。
2. 详情页组件(Detail.vue):电影信息和购票按钮
用户点击海报后,得展示电影简介和“选座购票”按钮。组件长这样:
<template>
<div class="detail">
<img :src="movie.poster" class="poster">
<h2>{{ movie.title }}</h2>
<p>{{ movie.description }}</p>
<button @click="buyTicket">选座购票</button>
</div>
</template>
<script>
export default {
data() {
return {
movie: {}
}
},
created() {
// 从路由参数获取电影ID,然后调API拿数据(这里用模拟数据)
const id = this.$route.params.id
this.movie = this.fetchMovieData(id)
},
methods: {
buyTicket() {
this.$router.push(`/seat/${this.movie.id}`)
}
}
}
</script>
关键技巧:
created生命周期钩子中,通过this.$route.params.id获取路由传递的电影ID;- 实际开发中,
fetchMovieData应该调用后端API,这里咱先用假数据模拟。
3. 选座页组件(Seat.vue):座位图和支付
最复杂的部分来了!要渲染座位图,并记录用户选中的座位:
<template>
<div class="seat-selection">
<h3>请选择座位(已选:{{ selectedSeats.join(', ') }})</h3>
<div class="screen">银幕在此</div>
<div class="seats">
<div
v-for="(row, index) in seats"
:key="index"
class="row"
>
<div
v-for="seat in row"
:key="seat.number"
:class="['seat', seat.status]"
@click="selectSeat(seat)"
>
{{ seat.number }}
</div>
</div>
</div>
<button @click="pay">支付</button>
</div>
</template>
<script>
export default {
data() {
return {
selectedSeats: [],
seats: [
[{ number: "1-1", status: "available" }, /* ...更多座位 */ ],
// ...更多排
]
}
},
methods: {
selectSeat(seat) {
if (seat.status === "available") {
seat.status = "selected"
this.selectedSeats.push(seat.number)
}
},
pay() {
this.$router.push("/order")
}
}
}
</script>
脑洞时刻:
- 座位状态用CSS类名控制,比如“available”是灰色,“selected”是红色;
- 实际项目还得考虑座位互斥(如不能单独选中间空位),这里先放水~
4. 订单页组件(Order.vue):展示订单信息
最后是订单页,简单展示购票结果:
<template>
<div class="order">
<h2>购票成功!🎉</h2>
<p>电影:{{ order.movieTitle }}</p>
<p>座位:{{ order.seats }}</p>
<button @click="goHome">再逛一圈</button>
</div>
</template>
四、路由配置:给APP装个GPS
光有组件不行,得用路由把它们串起来。在router/index.js中配置:
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/detail/:id', // 动态路由传电影ID
name: 'Detail',
component: () => import('../views/Detail.vue') // 懒加载,提速关键!
},
{
path: '/seat/:id',
name: 'Seat',
component: () => import('../views/Seat.vue')
},
{
path: '/order',
name: 'Order',
component: () => import('../views/Order.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
路由骚操作总结:
- 动态路由:用
/detail/:id匹配不同电影,ID通过$route.params.id获取; - 懒加载:
import()语法实现按需加载,让首页不用一次性加载所有组件; - History模式:去掉URL中的
#,颜值党必备(部署时需服务器配合)。
五、彩蛋环节:路由守卫的妙用
如果想在用户离开选座页时弹出确认框,防止误操作,可以用路由守卫:
// 在router/index.js中添加
router.beforeEach((to, from, next) => {
if (from.name === 'Seat' && to.name !== 'Order') {
const confirmLeave = confirm("选座信息未保存,确定离开?")
if (!confirmLeave) return next(false)
}
next()
})
这就实现了“渣男分手确认式”导航拦截!
六、完整示例打包
由于代码太长,这里提供Github仓库地址(模拟):
https://github.com/xxx/movie-ticket-demo
(实际写文章时需提供真实可运行代码目录结构)
七、结语:你离全栈只差一步
通过这个项目,你不仅学会了Vue组件拆分和路由配置,更重要的是掌握了“组件化思维”——把复杂页面拆成独立、可复用的零件。下次遇到更复杂的需求(比如加个购物车、用户评论),照葫芦画瓢就行!

被折叠的 条评论
为什么被折叠?



