前言:什么是路由
1.对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
A : http://127.0.0.1:5500/12.路由的使用.html/register
B : http://127.0.0.1:5500/12.路由的使用.html/login
app.get("/login",(req,res)=>{})
app.get("/register",(req,res)=>{})
当我们的网址由A到B的时候,此时会向服务器发送请求(也就是此时服务器要处理login请求)
2.对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时hash有一个特点,HTTP请求中不会包含hash相关的内容;
A : http://127.0.0.1:5500/12.路由的使用.html#/register
B : http://127.0.0.1:5500/12.路由的使用.html#/login
当我们的网址由A到B的时候,此时网址中变化是#后面的内容,此时不会向服务器发送请求。这种方式我们称为前端路由。
当我们由#/register切换到#/login变化的是:当前的路由地址所对应的组件信息
3.在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);
一、路由配置
1-1 安装依赖
yarn add vue-router
1-2 在App.vue
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
1-3 在routers文件夹下
//index.js
import Vue from 'vue';
import Router from 'vue-router'
import Music from '@/pages/Music.vue'
import Mv from '@/pages/Mv.vue'
Vue.use(Router);
export default new Router({
mode:"hash", //history
routes:[
{
path:'/music',
name:"music",
component:Music
},
{
path:'/mv',
name:"mv",
component:Mv
}
]
})
1-3-1 异步路由
进入页面时才会触发路由
export default new Router({
mode:"hash",
routes:[
...
{
path:"/detail",
name:"detail",
/* 异步路由 */
component:()=>import('@/pages/Detail')
}
]
})
1-4 在main.js下
import router from './routers'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
二、router-link 切换组件
//App.vue下
<template>
<div id="app">
<div id="nav">
<router-link to="/music">音乐</router-link>
<router-link to="/mv">MV</router-link>
</div>
<router-view></router-view>
</div>
</template>
常用属性:
属性 | 类型 | 说明 | 示例 |
---|---|---|---|
to | string \ Location | 表示目标路由的链接。当被点击后,内部会立刻把to 的值传到router.push() ,所以这个值可以是一个字符串或者是描述目标位置的对象。 |
<router-link to="home">Home</router-link> |
replace | boolean(默认flase) | 设置replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录 。 |
<router-link :to="{ path: '/abc'}" replace></router-link> |
append | boolean(默认flase) | 设置append 属性后,则在当前 (相对) 路径前添加基路径。例如,我们从 /a 导航到一个相对路径 b ,如果没有配置 append ,则路径为/b ,如果配了 ,则为/a/b |
<router-link :to="{ path: 'relative/path'}" append></router-link> |
tag | string(默认 ‘a’) | 有时候想要 渲染成某种标签,例如 <li> 于是我们使用tag prop 类指定何种标签,同样它还是会监听点击 ,触发导航。 |
<router-link to="/foo" tag="li">foo</router-link> |
active-class | string(默认 “router-link-active”) | 设置 链接激活时 使用的CSS 类名 。默认值可以通过路由的构造选项linkActiveClass 来全局配置。 |
|
exact | boolean(默认 false) | “是否激活” 默认类名的依据是 inclusive match (全包含匹配) 。 举个例子,如果当前的路径是 /a 开头的,那么 也会被设置 CSS 类名。 |
这个链接只会在地址为 / 的时候被激活: <router-link to="/" exact> |
event | string \ Array (默认 ‘click’) | 声明可以用来触发导航的事件 。可以是一个字符串 或是一个包含字符串的数组 。 |
|
exact-active-class | string 默认 ‘router-link-exact-active’ | 配置当链接被精确匹配的时候应该激活的 class 。注意默认值也是可以通过路由构造函数选项linkExactActiveClass 进行全局配置的。 |
三、路由传值
3-1 动态路由
传参:
<router-link :to="'/detail/'+item.id" tag="button">
跳转到detail
</router-link>
接收传参:
this.$route.params.id;
router配置
主页
详情页
3-2 get传值
3-2-1 在列表页传值this.$router.push()
<div @click="handleClick(data.id)"></div>
<router-link :to=`/detail?id=${id}` tag="button">
跳转到detail
</router-link>
export default {
name:"Item",
props:{
data:{
type:Object,
required:true
}
},
methods:{
handleClick(id){
console.log(id)
this.$router.push(`/detail?id=${id}`)
}
}
};
3-2-2 在详情页接收值this.$route.query
export default {
name:"Detail",
computed:{
id(){
return this.$route.query.id
}
}
};
mouted(){
var id = this.$route.query.id
}
3-2-3 在详情页跳转回列表页
methods: {
toggle() {
this.$router.back();
}
}
3-3 关于路由跳转
3-3-1 router-link方式
不带参数:
<router-link :to="{name:'home'}">
带参数:params传参数
html 取参 $route.params.id
script 取参 this.$route.params.id
<router-link :to="{name:'home', params: {id:1}}">
带参数:query传参数 (类似get,url后面会显示参数)
注意点:如果使用path,name不可以和params共用
html 取参 $route.query.id
script 取参 this.$route.query.id
<router-link :to="{name:'home', query: {id:1}}">
3-3-2 this.$router.push() 编程式导航
不带参数:
this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})
query传参:
this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})
params传参:
params只能用name来引入路由,不能与path一起用
this.$router.push({name:'home',params: {id:'1'}})
注:
- query类似get,跳转之后页面url后面会拼接参数,类似?id=1,非重要性的可以这样传,密码之类还是用params刷新页面id还在;
- params类似post,跳转之后页面url后面不会拼接参数,但是刷新页面id会消失。
3-4 route和router的区别
$route
是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。$router
是“路由实例”对象,包括了路由的跳转方法,钩子函数等。
3-5 meta的使用
meta字段(元数据),直接在路由配置的时候,给每个路由添加一个自定义的meta对象,在meta对象中可以设置一些状态,供页面组件或者路由钩子函数中使用。
<body>
<div id="app">
<div>
<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link>
<keep-alive>
<router-view v-if="$route.meta.cache"></router-view>
</keep-alive>
<!-- 不缓存 -->
<router-view v-if="!$route.meta.cache"></router-view>
</div>
</div>
<script>
var login = {
template: '<h3>登录<input type="text"></h3>'
}
var register = {
template: '<h3>注册<input type="text"></h3>'
}
var router = new VueRouter({
routes: [
{ path: '/login',
component: login ,
meta: {
cache: false
}
},
{ path: '/register',
component: register,
meta: {
cache: true
}
}
]
})
// 创建Vue实例得到ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
</body>
四、子路由,路由重定向
五、keep-alive
keep-alive 包裹路由-组件。 缓存组件 之后组件不会被销毁 组件对应的几个生命周期函数不会重新触发
当组件在
<keep-alive>
内被切换,它的activated
和deactivated
这两个生命周期钩子函数将会被对应执行5-1 解决mounted生命周期不执行的问题
第一种:在activated生命周期函数里面进行http请求
- 第二种:exclude
Tip:exclude绑定的组件不受keep-alive限制
//detail.vue页面
1.exclude Tips:一定要给组件name属性
export default {
name: "Detail",
data() {
return {
imgUrl: ""
};
},
mounted() {
...
}
};
</script>
//App.vue页面
2.配置keep-alive
<keep-alive exclude="Detail">
<router-view />
</keep-alive>
5-2 实现组件缓存功能
vue-cli工程中实现某个组件的缓存功能,可用 keep-alive 标签与 vue-router的meta形式数据传递配合完成。
//第一步:在 app.vue 里面 template部分 使用 <keep-alive></keep-alive> 组件:
<template>
<div id="app">
<keep-alive>
<router-view v-if="$router.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$router.meta.keepAlive"></router-view>
</div>
</template>
//第二步:在src/router.js:
import account from '../page/demo/account.vue'
import course from '../page/demo/course.vue'
export default new Router({
routes: [
{
path: '/account',
name: 'account',
component: Account,
meta:{
keepAlive:false //false为不缓存
}
},
{
path: '/course',
name: 'course',
component: course,
meta:{
keepAlive:true //true为缓存
}
}
]
})
六、命名路由
//配置
{
path: '/detail',
/* 命名路由 */
name: 'detail',
component: () => import('../views/Detail.vue')
}
6-1 router-link,get
<router-link :to="{name:'detail',query:{id:1213}}">detail</router-link>
6-2 router-link,动态路由
//配置动态路由
{
path: '/detail/:id',
/* 命名路由 */
name: 'detail',
component: () => import('../views/Detail.vue')
}
//配置router-link
<router-link :to="{name:'detail',params:{id:1213}}">detail</router-link>
6-3 $router.push()
this.$router.push({name:"detail",params:{id:1314}})
6-4 props解耦id
//配置路由
{
path: '/detail/:id',
/* 命名路由 */
name:'detail',
component:() => import('../views/Detail.vue'),
//core code
props:true
}
//Detail.vue
export default {
props:['id'],
mounted(){
console.log(this.id)
}
};
七、路由守卫
7-1 全局守卫
router.beforeEach router.beforeResolve router.afterEach
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
'''
const router = new VueRouter({
mode: 'history',
routes
})
router.beforeEach((to, from, next) => {
//to 将要访问的路径
//from 代表从哪个路径跳转而来
//next 是一个函数,表示放行
// next() 放行 next('/login') 强制跳转
if (to.path === '/login') return next();
//获取缓存
const tokenStr = window.sessionStorage.getItem('token')
//如果没有值,则强制跳转login页面,有则放行
if (!tokenStr) return next('/login')
next()
})
export default router
const router = new VueRouter({ ... });
router.beforeEach((to, from, next) => {
// do someting
});
//to:代表要进入的目标,它是一个路由对象
//from:代表当前正要离开的路由,同样也是一个路由对象
//next:这是一个必须需要调用的方法,而具体的执行效果则依赖 next 方法调用的参数
//全局后置钩子,后置钩子并没有 next 函数,也不会改变导航本身
router.afterEach((to, from) => {
// do someting
});
7-2 路由独享守卫
路由独享的守卫: beforeEnter
cont router = new VueRouter({
routes: [
{
path: '/file',
component: File,
beforeEnter: (to, from ,next) => {
// do someting
}
}
]
});
7-3 局部守卫(组件内守卫)
beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave
const File = {
template: `<div>This is file</div>`,
beforeRouteEnter(to, from, next) {
// do someting
// 在渲染该组件的对应路由被 confirm 前调用
},
beforeRouteUpdate(to, from, next) {
// do someting
// 在当前路由改变,但是依然渲染该组件是调用
},
beforeRouteLeave(to, from ,next) {
// do someting
// 导航离开该组件的对应路由时被调用
}
}
进入/center路由模块之前如何没有登陆授权,则进入登陆页面
//Center.vue
export default {
beforeRouteEnter(to,from,next){
if(false){
next()
}else{
next('/login')
}
}
}
export default {
beforeRouteEnter(to,from,next){
//登陆成功则跳转
if(true){
next()
}else{
next('/login')
}
}
}
路由守卫:主要就是全局守卫、路由独享守卫、局部守卫
1、全局守卫:是指路由实例上直接操作的钩子函数,特点是所有路由配置的组件都会触发,直白点就是触发路由就会
触发这些钩子函数
router.beforeEach((to,from,next)=>{})
回调函数中的参数,to:进入到哪个路由去,from:从哪个路由离开,next:函数,决定是否展示你要看到的
路由页面
2、路由独享守卫:是指在单个路由配置的时候也可以设置的钩子函数
beforeEnter:(to,from,next)=>{}
3、局部守卫:是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩
子函数
beforeRouteEnter:(to,from,next)=>{}
7-4 路由跳转导航解析流程
当由A路由 —> B路由的时候:
a、在A组件里调用离开守卫。 A组件中的 beforeRouteLeave
b、调用全局的 beforeEach 守卫。 router.beforeEach
c、再执行B路由配置里调用 beforeEnter。
routes: [
{
path: '/b',
component: B,
beforeEnter: (to, from, next) => {
}
}
]
d、再执行B组件的进入守卫。 B组件中 beforeRouteEnter。
e、调用全局的 beforeResole 守卫 (2.5+)。 router.beforeResolve
f、导航被确认。
g、调用全局的 afterEach 钩子。 router.afterEach
h、触发 DOM 更新。
7-4 例子
全局守卫:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
'''
const router = new VueRouter({
mode: 'history',
routes
})
router.beforeEach((to, from, next) => {
//to 将要访问的路径
//from 代表从哪个路径跳转而来
//next 是一个函数,表示放行
// next() 放行 next('/login') 强制跳转
if (to.path === '/login') return next();
//获取缓存
const tokenStr = window.sessionStorage.getItem('token')
//如果没有值,则强制跳转login页面,有则放行
if (!tokenStr) return next('/login')
next()
})
export default routerCopy to clipboardErrorCopied
局部守卫:beforeRouteEnter不能获取组件实例"this",但我们通过传一个回调给next,就可以使用vm来访问组件实例
<script>
export default {
data(){
return{
name:"Arya"
}
},
beforeRouteEnter:(to,from,next)=>{
next(vm=>{
alert("hello" + vm.name);
})
}
}
</script>