Vue路由
路由基本知识
Vue Router
是Vue.js
的官方路由。它与Vue.js
核心深度集成,使用Vue.js
构建单页面应用变得轻而易举。
功能包括:
- 嵌套路由映射
- 动态路由选择
- 模块化、基于组件的路由配置
- 路由参数、查询、通配符
- 展示由Vue.js的过渡系统提供的过渡效果
- 细致的导航控制
- 自动激活CSS类的链接
- HTML5 history 模式或hash模式
- 可定制的滚动行为
- url的正确编码
安装Vue Router
npm instal vue-router@4
added 2 packages, and audited 29 packages in 2s
4 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
新建一个项目:
npm create vite@latest
✔ Project name: … vue_test03
✔ Select a framework: › Vue
✔ Select a variant: › JavaScript
Scaffolding project in /Users/laobai/TempProjects/vue_test03...
Done. Now run:
cd vue_test03
npm install
npm run dev
安装包
npm install
added 26 packages, and audited 27 packages in 10s
3 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
启动服务
npm run dev
> vue_test03@0.0.0 dev
> vite
VITE v4.4.9 ready in 332 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h to show help
路由基本配置使用
在src目录下创建router目录存放index.js路由配置文件,创建views目录存放子组件文件。
src—VueRouter—router—index.js
src—VueRouter—views—Lists.vue
src—VueRouter—views—My.vue
src—VueRouter—App.vue
src—main.js
index.js
// 配置路由
import { createRouter, createWebHashHistory } from 'vue-router'
import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
const routes = [
{
path:"/my",
component:My
},
{
path:"/lists",
component:Lists
},
]
const router = createRouter({
history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
routes, // routers: routes 的缩写
})
export default router
App.vue
<router-view/>
负责显示路径对应的组件内容
组件显示的出口,是根据用户输入的path显示对应的组件 (在index.js
中配置)
<template>
<div>
App
<!-- 通过插槽插入子组件路由 -->
<router-view></router-view>
</div>
</template>
Lists.vue
<template>
<div>
lists
</div>
</template>
My.vue
<template>
<div>
my
</div>
</template>
main.js
在main.js
中注册/挂载路由,才可以在页面中通过<router-view/>
显示出来
import { createApp } from 'vue'
import './style.css'
import App from './VueRouter/App.vue'
import router from './VueRouter/router'
let app = createApp(App)
app.use(router) // 注册路由插件
app.mount("#app")
为/
根路径配置重定向
// 配置路由
import { createRouter, createWebHashHistory } from 'vue-router'
import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
const routes = [
{
path:"/my",
component:My
},
{
path:"/lists",
component:Lists
},
// 设置访问根节点时重定向到/lists
{
path:"/",
redirect:"/lists"
}
]
const router = createRouter({
history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
routes, // routers: routes 的缩写
})
export default router
在上面的基础上,可以为每个路径配置的组件设置一个名字
// 配置路由
import { createRouter, createWebHashHistory } from 'vue-router'
import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
const routes = [
{
path:"/my",
name:"my",
component:My
},
{
path:"/lists",
name:"lists", // 命名路由
component:Lists
},
// 设置访问根节点时重定向到/lists
{
path:"/",
// redirect:"/lists"
redirect:{
name:"lists"
}
}
]
const router = createRouter({
history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
routes, // routers: routes 的缩写
})
export default router
针对访问不存在的路径,配置404路由
增加NotFound.vue
<template>
<div>
404 not found
</div>
</template>
修改index.js
// 配置路由
import { createRouter, createWebHashHistory } from 'vue-router'
import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
import NotFound from '../views/NotFound.vue'
const routes = [
{
path:"/my",
name:"my",
component:My
},
{
path:"/lists",
name:"lists",
component:Lists
},
// 设置访问根节点时重定向到/lists
{
path:"/",
// redirect:"/lists"
redirect:{
name:"lists"
}
},
{
path:"/:pathMatch(.*)*",
name:"NotFound",
component: NotFound
}
]
const router = createRouter({
history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
routes, // routers: routes 的缩写
})
export default router
声明式导航
在VueRouter目录下创建components目录,创建Tabbar.vue

通过<router-link to="">
来实现页面跳转(单页面应用,不会刷新页面)
<template>
<div class="tabbar">
<ul>
<router-link custom to="/lists" v-slot="{isActive,navigate}">
<li :class="isActive?'plactive':''" @click="navigate">商品列表</li>
</router-link>
<router-link custom to="/my" v-slot="{isActive,navigate}">
<li :class="isActive?'plactive':''" @click="navigate">我的</li>
</router-link>
</ul>
</div>
</template>
<style scoped lang="scss">
.plactive{
color: red;
}
.tabbar{
position: fixed;
bottom: 0;
width:100%;
height: 50px;
line-height: 50px;
text-align: center;
ul{
display: flex;
li {
flex: 1;
}
}
}
</style>
路由index.js
// 配置路由
import { createRouter, createWebHashHistory } from 'vue-router'
import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
import NotFound from '../views/NotFound.vue'
const routes = [
{
path:"/my",
name:"my",
component:My
},
{
path:"/lists",
name:"lists",
component:Lists
},
// 设置访问根节点时重定向到/lists
{
path:"/",
// redirect:"/lists"
redirect:{
name:"lists"
}
},
{
path:"/:pathMatch(.*)*",
name:"NotFound",
component: NotFound
}
]
const router = createRouter({
history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
routes, // routers: routes 的缩写
})
export default router
App.vue
<template>
<div>
<!-- 通过插槽插入子组件路由 -->
<router-view></router-view>
<!-- 增加导航 -->
<Tabbar></Tabbar>
</div>
</template>
<script>
import Tabbar from './components/Tabbar.vue';
export default {
components:{
Tabbar
}
}
</script>
<style>
*{
margin: 0;
padding: 0;
}
ul{
list-style: none;
}
</style>

嵌套路由
在路由中创建子路由,对应上面的例子中即为商品列表中包多个子列表,比如最新商品、推荐商品等。
Lists.vue同级目录中创建lists目录,在其中创建两个子文件New.vue和Recommend.vue
<template>
<div>
new
</div>
</template>
<template>
<div>
recommond
</div>
</template>
在index.js中导入上面两个文件,并在lists路由中加入子路由
// 配置路由
import { createRouter, createWebHashHistory } from 'vue-router'
import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
import NotFound from '../views/NotFound.vue'
import New from '../views/lists/New.vue'
import Recommend from '../views/lists/Recommend.vue'
const routes = [
{
path:"/my",
component:My
},
{
path:"/lists",
component:Lists,
// 增加子路由
children:[
{
path:"/lists/new",
component:New
},
{
path:"recommend",
component:Recommend
},
// 访问lists页重定向到recommend
{
path:"/lists",
redirect:'/lists/recommend'
}
]
},
// 设置访问根节点时重定向到/lists,即访问根目录直接访问到lists页
{
path:"/",
redirect:"/lists"
// 若要匹配多级路由,只能用上面的写法,下面的写法无法匹配多级路由
// redirect:{
// name:"lists"
// }
},
{
path:"/:pathMatch(.*)*",
name:"NotFound",
component: NotFound
}
]
const router = createRouter({
history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
routes, // routers: routes 的缩写
})
export default router
上面的代码中,两次使用到了重定向redirect
,均是为页面设置默认展示的内容。
在Lists.vue中增加子路由,即最新商品和推荐商品等
<template>
<div>
<div style="height:100px;line-height: 100px;text-align: center;">轮播图</div>
<ul class="lists">
<router-link custom to="/lists/new" v-slot="{ isActive, navigate }">
<!-- <li >最新商品</li> -->
<li @click="navigate">
<span :class="isActive ? 'plactive' : ''" >最新商品</span>
</li>
</router-link>
<router-link custom to="/lists/recommend" v-slot="{ isActive, navigate }">
<li @click="navigate">
<span :class="isActive ? 'plactive' : ''" >推荐商品</span>
</li>
</router-link>
</ul>
<router-view></router-view>
</div>
</template>
<style scoped lang="scss">
.lists {
display: flex;
height: 50px;
line-height: 50px;
text-align: center;
li {
flex: 1;
list-style: none;
span{
padding:10px 0;
}
}
}
.plactive {
color: red;
border-bottom: 3px solid red;
}
</style>

编程式导航
编程式一般用于在js中,使用this.$router.push()
方法来进行
<template>
<div>
<ul>
<!-- 声明式 -->
<!-- <router-link custom :to="'/detail/'+item.filmId" v-slot="{navigate}" v-for="item in datalist" :key="item.filmId">
<li @click="navigate">
{{item.name}}
</li>
</router-link> -->
<!-- 编程式 -->
<li v-for="item in datalist" :key="item.filmId" @click="plClick(item.filmId)">
{{item.name}}
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default{
data(){
return{
datalist:[]
}
},
async mounted(){
const res = await axios({
url:"https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=3317109",
headers:{
'X-Client-Info':'{"a":"3000","ch":"1002","v":"5.2.1","e":"16931924276063063597842433","bc":"110100"}',
'X-Host':'mall.film-ticket.film.list'
}
})
this.datalist = res.data.data.films
console.log(this.datalist)
},
methods:{
plClick(id){
this.$router.push(`/detail/${id}`)
}
}
}
</script>
<style scoped lang="scss">
ul{
li{
padding:10px;
}
}
</style>
动态路由匹配
上面增加了detail商品详情,而在商品详情页url中商品id是根据访问的商品动态变化的
新建Detail.vue文件
<template>
<div>
<button @click="plBackClick">返回</button>
detail
</div>
</template>
<script>
export default {
mounted(){
console.log('接收上一个页面传来的参数',this.$route.params.plid)
},
methods:{
plBackClick(){
this.$router.back() // 返回 this.$router.forward()
}
}
}
</script>
在路由配置文件index.js中导入并配置路由
// 配置路由
import { createRouter, createWebHashHistory } from 'vue-router'
import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
import NotFound from '../views/NotFound.vue'
import New from '../views/lists/New.vue'
import Recommend from '../views/lists/Recommend.vue'
import Detail from '../views/Detail.vue'
const routes = [
{
path:"/my",
component:My
},
{
path:"/lists",
component:Lists,
// 增加子路由
children:[
{
path:"/lists/new",
component:New
},
{
path:"recommend",
component:Recommend
},
// 访问lists页重定向到recommend
{
path:"/lists",
redirect:'/lists/recommend'
}
]
},
{
name:'detail',
path:'/detail/:plid',
component:Detail
},
// 设置访问根节点时重定向到/lists,即访问根目录直接访问到lists页
{
path:"/",
redirect:"/lists"
// 若要匹配多级路由,只能用上面的写法,下面的写法无法匹配多级路由
// redirect:{
// name:"lists"
// }
},
{
path:"/:pathMatch(.*)*",
name:"NotFound",
component: NotFound
}
]
const router = createRouter({
history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
routes, // routers: routes 的缩写
})
export default router
修改列表页New.vue
<template>
<div>
<ul>
<!-- 声明式 -->
<!-- <router-link custom :to="'/detail/'+item.filmId" v-slot="{navigate}" v-for="item in datalist" :key="item.filmId">
<li @click="navigate">
{{item.name}}
</li>
</router-link> -->
<!-- 编程式 -->
<li v-for="item in datalist" :key="item.filmId" @click="plClick(item.filmId)">
{{item.name}}
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default{
data(){
return{
datalist:[]
}
},
async mounted(){
const res = await axios({
url:"https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=3317109",
headers:{
'X-Client-Info':'{"a":"3000","ch":"1002","v":"5.2.1","e":"16931924276063063597842433","bc":"110100"}',
'X-Host':'mall.film-ticket.film.list'
}
})
this.datalist = res.data.data.films
console.log(this.datalist)
},
methods:{
plClick(id){
this.$router.push(`/detail/${id}`)
}
}
}
</script>
<style scoped lang="scss">
ul{
li{
padding:10px;
}
}
</style>
路由模式
前面介绍的内容都是基于哈希模式实现,最直观的效果就是url中主机及端口后方有个#,例如:http://localhost:5173/#/lists/new
,个人不是很喜欢这种url。
可以在创建路由时使用createWebHistory()
进行创建
const router = createRouter({
// history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
history: createWebHistory(),
routes, // routers: routes 的缩写
})
全局路由拦截
新建Login.vue
<template>
<div>
<h3>login页面</h3>
<button @click="plClick">登录</button>
</div>
</template>
<script>
export default{
methods:{
plClick(){
localStorage.setItem("token","plscript")
this.$router.push("/")
}
}
}
</script>
修改路由文件index.js,进行请求拦截,满足条件的才可以继续执行
// 配置路由
import { createRouter, createWebHashHistory,createWebHistory } from 'vue-router'
import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
import NotFound from '../views/NotFound.vue'
import New from '../views/lists/New.vue'
import Recommend from '../views/lists/Recommend.vue'
import Detail from '../views/Detail.vue'
import Login from '../views/Login.vue'
const routes = [
{
path:"/my",
component:My
},
{
path:"/lists",
component:Lists,
// 增加子路由
children:[
{
path:"/lists/new",
component:New
},
{
path:"recommend",
component:Recommend
},
// 访问lists页重定向到recommend
{
path:"/lists",
redirect:'/lists/recommend'
}
]
},
{
name:'detail',
path:'/detail/:plid',
component:Detail
},
{
name:'Login',
path:'/login',
component:Login
},
// 设置访问根节点时重定向到/lists,即访问根目录直接访问到lists页
{
path:"/",
redirect:"/lists"
// 若要匹配多级路由,只能用上面的写法,下面的写法无法匹配多级路由
// redirect:{
// name:"lists"
// }
},
{
path:"/:pathMatch(.*)*",
name:"NotFound",
component: NotFound
}
]
const router = createRouter({
// history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
history: createWebHistory(),
routes, // routers: routes 的缩写
})
// 全局拦截 beforeEach每次路由都进行拦截,to是要跳转的页面,from是从哪个页面跳过来的,next不执行就不会继续执行
router.beforeEach((to, from, next) =>{
// console.log(to.fullPath)
// console.log(from.fullPath)
let isAuthenticated = localStorage.getItem("token")
// 判断当前页面不是Login,并且localStorage中不含有token,跳转到登录页
if(to.name !== 'Login' && !isAuthenticated) next ({name:'Login'})
// 否则继续执行操作
else next()
})
export default router
这里使用的是beforeEach(to,from,next)
,会拦截全部的路由请求
可以拦截指定的一个或几个地址进行拦截
router.beforeEach((to, from, next) =>{
// console.log(to.fullPath)
// console.log(from.fullPath)
let isAuthenticated = localStorage.getItem("token")
// 判断当前页面不是Login,并且localStorage中不含有token,跳转到登录页
if(to.name !== 'Login' && !isAuthenticated && to.fullPath==='/my') next ({name:'Login'})
// 否则继续执行操作
else next()
})
还可以对需要进行拦截的添加meta
{
path:"/my",
component:My,
meta:{
requiredAuth:true
}
}
router.beforeEach((to, from, next) =>{
// console.log(to.fullPath)
// console.log(from.fullPath)
let isAuthenticated = localStorage.getItem("token")
// 判断当前页面不是Login,并localStorage中不含有token,且meta的requiredAuth为True,跳转到登录页
if(to.name !== 'Login' && !isAuthenticated && to.meta.requiredAuth) next ({name:'Login'})
// 否则继续执行操作
else next()
})
组件内的钩子
上面介绍了在路由配置文件中进行拦截,vue也提供了在组件内进行拦截的方法
修改my.vue
进入组件之前
<template>
<div>
my
</div>
</template>
<script>
export default{
// 进入路由
beforeRouteEnter(to, from, next){
let isAuthenticated = localStorage.getItem("token")
// 如果存在token,直接继续操作
if(isAuthenticated){
next()
// 如果没有token,跳转到登录页
}else{
next({name:"Login"})
}
}
}
</script>
更新组件之前
beforeRouteUpdate(to,from){
// console.log("beforeRouteUpdate",to)
console.log("接受猜你喜欢传来的参数",to.params.myid,"带着id参数请求后端接口")
}
离开组件之前
beforeRouteLeave(){
const answer = window.confirm("确定要离开吗?")
if(!answer) return false
}
路由懒加载
在打包构建应用时,JavaScript包会变得非常大,影响页面加载。为了提高加载效率,可以把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件。
Vue Router支持开箱即用的动态导入,这意味着可以用动态导入代替静态导入。
将原有导入组件路由的代码注释掉
// import My from '../views/My.vue'
在增加路由的位置导入对应组件路由
{
path:"/my",
// 使用箭头函数导入My.vue,即动态导入
component: ()=> import('../views/My.vue'),
meta:{
requiredAuth:true
}
}
VCA与路由
上面的例子是使用选项式API模式写的,这里改写成Vue3的组合式API模式(VCA)
src/main.js不用改
import { createApp } from 'vue'
import './style.css'
import App from './VueRouter/App.vue'
import router from './VueRouter/router'
let app = createApp(App)
app.use(router) // 注册路由插件
app.mount("#app")
scr/VueRouter/router/index.js不用改
// 配置路由
import { createRouter, createWebHashHistory,createWebHistory } from 'vue-router'
// import My from '../views/My.vue'
import Lists from '../views/Lists.vue'
import NotFound from '../views/NotFound.vue'
import New from '../views/lists/New.vue'
import Recommend from '../views/lists/Recommend.vue'
import Detail from '../views/Detail.vue'
import Login from '../views/Login.vue'
const routes = [
{
path:"/my",
component: ()=> import('../views/My.vue'),
meta:{
requiredAuth:true
}
},
{
path:"/lists",
component:Lists,
// 增加子路由
children:[
{
path:"/lists/new",
component:New
},
{
path:"recommend",
component:Recommend
},
// 访问lists页重定向到recommend
{
path:"/lists",
redirect:'/lists/recommend'
}
]
},
{
name:'detail',
path:'/detail/:plid',
component:Detail
},
{
name:'Login',
path:'/login',
component:Login
},
// 设置访问根节点时重定向到/lists,即访问根目录直接访问到lists页
{
path:"/",
redirect:"/lists"
// 若要匹配多级路由,只能用上面的写法,下面的写法无法匹配多级路由
// redirect:{
// name:"lists"
// }
},
{
path:"/:pathMatch(.*)*",
name:"NotFound",
component: NotFound
}
]
const router = createRouter({
// history: createWebHashHistory(), // hash模式 #/my #/list
// history普通模式 /my /list
history: createWebHistory(),
routes, // routers: routes 的缩写
})
// 全局拦截 beforeEach每次路由都进行拦截,to是要跳转的页面,from是从哪个页面跳过来的,next不执行就不会继续执行
// router.beforeEach((to, from, next) =>{
// // console.log(to.fullPath)
// // console.log(from.fullPath)
// let isAuthenticated = localStorage.getItem("token")
// // 判断当前页面不是Login,并且localStorage中不含有token,跳转到登录页
// if(to.name !== 'Login' && !isAuthenticated) next ({name:'Login'})
// // 否则继续执行操作
// else next()
// })
// 全局拦截 beforeEach每次路由都进行拦截,to是要跳转的页面,from是从哪个页面跳过来的,next不执行就不会继续执行
// router.beforeEach((to, from, next) =>{
// // console.log(to.fullPath)
// // console.log(from.fullPath)
// let isAuthenticated = localStorage.getItem("token")
// // 判断当前页面不是Login,并且localStorage中不含有token,跳转到登录页
// if(to.name !== 'Login' && !isAuthenticated && to.fullPath==='/my') next ({name:'Login'})
// // 否则继续执行操作
// else next()
// })
// router.beforeEach((to, from, next) =>{
// // console.log(to.fullPath)
// // console.log(from.fullPath)
// let isAuthenticated = localStorage.getItem("token")
// // 判断当前页面不是Login,并且localStorage中不含有token,跳转到登录页
// if(to.name !== 'Login' && !isAuthenticated && to.meta.requiredAuth) next ({name:'Login'})
// // 否则继续执行操作
// else next()
// })
export default router
scr/App.vue修改如下:
<template>
<div>
<!-- 通过插槽插入子组件路由 -->
<router-view></router-view>
<!-- 增加导航 -->
<Tabbar></Tabbar>
</div>
</template>
<script setup>
import Tabbar from './components/Tabbar.vue';
// export default {
// components:{
// Tabbar
// }
// }
</script>
<style>
*{
margin: 0;
padding: 0;
}
ul{
list-style: none;
}
</style>
scr/VueRouter/components/Tabbar.vue不用修改
<template>
<div class="tabbar">
<ul>
<router-link custom to="/lists" v-slot="{isActive,navigate}">
<li :class="isActive?'plactive':''" @click="navigate">商品列表</li>
</router-link>
<router-link custom to="/my" v-slot="{isActive,navigate}">
<li :class="isActive?'plactive':''" @click="navigate">我的</li>
</router-link>
</ul>
</div>
</template>
<style scoped lang="scss">
.plactive{
color: red;
}
.tabbar{
position: fixed;
bottom: 0;
width:100%;
height: 50px;
line-height: 50px;
background: white;
z-index: 100;
text-align: center;
ul{
display: flex;
li {
flex: 1;
}
}
}
</style>
src/VueRouter/views/Login.vue修改如下:
<template>
<div>
<h3>login页面</h3>
<button @click="plClick">登录</button>
</div>
</template>
<!-- <script>
export default{
methods:{
plClick(){
localStorage.setItem("token","plscript")
this.$router.push("/")
}
}
}
</script> -->
<script setup>
import {useRouter} from 'vue-router'
const router = useRouter()
const plClick = ()=>{
localStorage.setItem("token","plscript")
router.push("/")
}
</script>
src/VueRouter/views/List.vue不用修改。List.vue中的内容已经分离到Lists目录下的子文件
<template>
<div>
<div style="height:100px;line-height: 100px;text-align: center;">轮播图</div>
<ul class="lists">
<router-link custom to="/lists/new" v-slot="{ isActive, navigate }">
<!-- <li >最新商品</li> -->
<li @click="navigate">
<span :class="isActive ? 'plactive' : ''" >最新商品</span>
</li>
</router-link>
<router-link custom to="/lists/recommend" v-slot="{ isActive, navigate }">
<li @click="navigate">
<span :class="isActive ? 'plactive' : ''" >推荐商品</span>
</li>
</router-link>
</ul>
<router-view></router-view>
</div>
</template>
<style scoped lang="scss">
.lists {
display: flex;
height: 50px;
line-height: 50px;
text-align: center;
li {
flex: 1;
list-style: none;
span{
padding:10px 0;
}
}
}
.plactive {
color: red;
border-bottom: 3px solid red;
}
</style>
src/VueRouter/views/List/Recommend.vue不用修改
<template>
<div>
recommond
</div>
</template>
src/VueRouter/views/List/New.vue修改如下:
<template>
<div>
<ul>
<!-- 声明式 -->
<!-- <router-link custom :to="'/detail/'+item.filmId" v-slot="{navigate}" v-for="item in datalist" :key="item.filmId">
<li @click="navigate">
{{item.name}}
</li>
</router-link> -->
<!-- 编程式 -->
<li v-for="item in datalist" :key="item.filmId" @click="plClick(item.filmId)">
{{ item.name }}
</li>
</ul>
</div>
</template>
<script setup>
import axios from 'axios'
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
const datalist = ref([])
const router = useRouter()
onMounted(async() => {
const res = await axios({
url: "https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=3317109",
headers: {
'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"16931924276063063597842433","bc":"110100"}',
'X-Host': 'mall.film-ticket.film.list'
}
})
datalist.value = res.data.data.films
console.log(datalist.value)
})
const plClick = (id)=>{
router.push(`/detail/${id}`)
}
</script>
<style scoped lang="scss">
ul {
li {
padding: 10px;
}
}
</style>
src/VueRouter/views/Detail.vue修改如下:
<template>
<div>
<button @click="plBackClick">返回</button>
detail
</div>
</template>
<script setup>
import {onMounted} from 'vue'
import { useRoute,useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
onMounted(()=>{
console.log('接收上一个页面传来的参数',route.params.plid)
})
const plBackClick = ()=>{
router.back() // 返回 router.forward()
}
</script>
src/VueRouter/views/My.vue修改如下:
<template>
<div>
my
</div>
</template>
<script>
export default{
// 进入路由之前
beforeRouteEnter(to, from, next){
let isAuthenticated = localStorage.getItem("token")
// 如果存在token,直接继续操作
if(isAuthenticated){
next()
// 如果没有token,跳转到登录页
}else{
next({name:"Login"})
}
}
}
</script>
<script setup>
// VCA不支持onBeforeRouteEnter (这里使用了VCA和VOA结合的方式,但更推荐使用全局路由拦截的方式实现)
import { onBeforeRouteUpdate,onBeforeRouteLeave } from 'vue-router'
onBeforeRouteUpdate(()=>{
console.log("beforeRouteUpdate")
})
onBeforeRouteLeave(()=>{
const answer = window.confirm("你确定要离开吗?")
if(!answer) return false
})
</script>
VCA不支持onBeforeRouteEnter
(这里使用了VCA和VOA结合的方式,但更推荐使用全局路由拦截的方式实现)
附:路由分类
- 后端路由:
- 理解:value是function,用于处理客户端提交的请求;
- 工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据;
- 前端路由:
- 理解:value是component,用于展示页面内容;
- 工作过程:当浏览器的路径改变时,对应的组件就会显示;