1. vue cli 创建一个项目
我们会用到 vue-router
在 views 中创建组件 ,Center.vue、Cinermas.vue、Detail.vue、Films.vue、Login.vue、Order.vue、Search.vue(分别是我的,影院,详情,电影,登录,搜索,订单)。
这只是一个大概框架。
再创建 films 文件,因为 在 电影页面中包含两个子组件,一个是正在热映 hotplaying.vue 组件,一个是预告电影 Comingsoon.vue.
当点击“我的” 展示用户信息。点击 “ 订单” 展示订单购票信息。点击 “ 影院” 展示附近的影院列表。
点击 “电影” 展示 最近正在热映的电影和预告电影,点击 ”搜索“ 搜索电影。当用户还未登录时,点击 “我的” 会跳转到“登录” 组件。
在 根组件 App.vue 中 显示三个菜单,点击一个菜单,该菜单高亮,进行组件之间的切换。v-slot 传回一个对象,navigate,表示点击的哪一个,isActive 就为 true ,class 值就为 myactive ,否则为 空。(class 用来设置高亮样式。) 详细内容可以见 https:// router.vuejs.org 路由官方文档。
<template>
<div>
<header>Welcome to Exciting Cinema</header>
<ul>
<router-link to="/films" custom v-slot="{navigate,isActive}">
<li @click="navigate" :class="isActive?'myactive':''">
电影--{{isActive}}
</li>
</router-link>
<router-link to="/cinermas" custom v-slot="{navigate,isActive}">
<li @click="navigate" :class="isActive?'myactive':''">
影院--{{isActive}}
</li>
</router-link>
<router-link to="/center" custom v-slot="{navigate,isActive}">
<li @click="navigate" :class="isActive?'myactive':''">
我的--{{isActive}}
</li>
</router-link>
</ul>
<!-- 路由容器 相当于插槽 -->
<!-- router.vuejs.org 路由官方文档 -->
<router-view></router-view>
</div>
</template>
在 router 文件下 index.js 打开 注册并且引入路由
import Vue from 'vue'
import VueRouter from 'vue-router'
import Films from '@/views/Films'
import Cinermas from '@/views/Cinermas'
import Login from '@/views/Login'
import Hotplaying from '@/views/films/Hotplaying'
import Comingsoon from '@/views/films/Comingsoon'
import Search from '@/views/Search'
import Detail from '@/views/Detail'
Vue.use(VueRouter) // 注册路由插件
// 配置表
const routes = [
{
path: '/films',
component: Films,
// 二级路由(嵌套路由)
children: [
{
path: '/films/hotplaying',
component: Hotplaying
},
{
path: '/films/comingsoon',
component: Comingsoon
},
{
path: '/films',
redirect: '/films/hotplaying'
}
]
},
{
name: 'mydetil', // 命名路由
path: '/detail/:myid', // 动态二级路由
component: Detail
},
{
path: '/cinermas',
component: Cinermas
},
{
path: '/cinermas/search',
component: Search
},
{
path: '/order',
// 路由懒加载的方式,当需要这个组件出现了这个路径之后再加载 js 文件
component: () => import('@/views/Order'),
meta: {
isMyrequired: true
}
},
{
path: '/login',
component: Login
},
{
path: '/center',
component: () => import('@/views/Center'),
meta: {
isMyrequired: true
}
},
{
// 路由重定向 * 通配符匹配所有
path: '*',
redirect: '/films'
}
]
const router = new VueRouter({
mode: 'history', // 地址就没有 # 号了
routes
})
router.beforeEach((to, from, next) => {
console.log(to.fullPath)
console.log(to)
if (to.meta.isMyrequired) {
// 判断本地存储中是否有 token 字段
if (localStorage.getItem('token')) {
next()
} else {
next({
path: '/login',
query: { myredirect: to.fullPath }
}) // 重定向到 login 页面 , 并记录从哪儿来的,以备登录成功后再跳转回去。
}
} else {
next()
}
})
export default router
当用户在电影页面时。访客可以点击正在热映和预告电影。这里使用了嵌套路由,也可说是二级路由。因为访客不离开电影页面,只是页面内的两个组件切换。
{
path: '/films',
component: Films,
// 二级路由(嵌套路由)
children: [
{
path: '/films/hotplaying',
component: Hotplaying
},
{
path: '/films/comingsoon',
component: Comingsoon
},
{
path: '/films',
redirect: '/films/hotplaying'
}
]
},
最后一个路由 是始终保持电影页面默认显示 正在热映 组件 采用了重定向。
用了重定向的地方还有这里,当访客在地址栏后面输入无效内容时都会默认跳转到 这个电影界面。
{
// 路由重定向 * 通配符匹配所有
path: '*',
redirect: '/films'
}
当访客点击某一个 正在热映的电影时,需要加载这个电影的详情,这里使用动态路由。每一个电影用不通的id 标识。
{
name: 'mydetil', // 命名路由
path: '/detail/:myid', // 动态二级路由
component: Detail
},
当未登录的用户点击“我的”或者查看订单时需要对其跳转进行拦截至登录页 Login.vue。登陆后才能跳转。这里采用的时全局拦截格式如下。
// 全局拦截
/*
router.beforeEach((to,from,next)=>{
console.log(to)
if(某几个需要授权的路由){
if(授权通过){
next()
}else{
next('/login') // 重定向到 login 页面
}
}else{
next()
}
})
*/
同时我们希望 能够记住用户在跳转登录前的页面,用户登录以后再跳转回来页面。
这里我们模拟用 token 字段来验证用户有无登录
if (to.meta.isMyrequired) {
// 判断本地存储中是否有 token 字段
if (localStorage.getItem('token')) {
next()
在需要拦截的 路径我们加了 meta 用来标记
{
path: '/center',
component: () => import('@/views/Center'),
meta: {
isMyrequired: true
}
这是路由懒加载的引入方式,因为当组件很多时,提高首页加载的速度,访客点击了其他的内容再去加载相应的 js 文件。
component: () => import('@/views/Center')
接下来来到 login.vue
<template>
<div>
登录页面
<button @click="handlogin()">登录</button>
</div>
</template>
<script>
export default {
methods: {
handlogin () {
setTimeout(() => {
localStorage.setItem('token', '后端返回的 token 字段')
// this.$router.back() // 返回
// 1. 获取 query 字段
console.log(this.$route.query.myredirect)
// 2. 跳转到跳转之前的界面。
this.$router.push(this.$route.query.myredirect)
}, 2000)
}
}
}
</script>
表示跳转到登录页面之前我是在 这个路径下 的页面。query 是我们上面拦截路由时所传的一个对象。
films.vue 这里用的声明式导航的另一种写法。因为导航栏不多可以手写。
<template>
<div>
<div class="lun">轮播</div>
<ul>
<router-link to="/films/hotplaying" tag="li" active-class="play_class">正在热映</router-link>
<router-link to="/films/comingsoon" tag="li" active-class="play_class">即将上映</router-link>
</ul>
<router-view></router-view>
</div>
</template>
detail.vue 当点击正在热映列表电影的时候就会显示页面创建完成。获得id和路径 .页面创建完成了
<template>
<div>
detail
</div>
</template>
<script>
export default {
created () {
console.log('created', this.$route)
},
mounted () {
console.log('mounted', this.$route.params.myid)
}
}
</script>
hotplaing.vue 制造一个一一些假数据。这里介绍了点击跳转的三种方式。最后我们用了通过命名路由跳转方式。
<template>
<div>
hotplaying
<ul>
<li v-for="items in datalist" :key="items" @click="handetail(items)">{{items}}</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
datalist: ['1111', '2222', '3333']
}
},
methods: {
handetail (id) {
// 编程式导航
// location.href = '#/detail'
// 通过路劲跳转
// this.$router.push(`/detail/${id}`)
// 通过命名路由跳转
this.$router.push({
name: 'mydetil',
params: {
myid: id
}
})
}
}
}
</script>
因为要考虑不同设备大小的兼容性,这里使用 rem 等比例缩放。
在index.html 文件中设置等比例缩放,这里 750 *16 都是可以更改的。不过 px to rem 默认是16 ,如果更改也需要同步更改 px to rem 配置。
<script>
// font-size 计算
document.documentElement.style.fontSize=document.documentElement.clientWidth/750*16+'px'
</script>
以及 px to rem 小工具来帮助我们实现 px 到 rem 的自动转换,px to rem 默认的是 16px
未完待续