目录
路由
含义:一个路由就是一组映射关系(key-value)
理解:key为路径,value可能是function或component
路由的分类
后端路由
- 理解:value为function,用于处理客户端提交的请求
- 工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据
前端路由
- 理解:value为component,用于展示页面内容
- 工作过程:当浏览器的路径改变时,对应的组件就会显示
vue中路由的使用
引入路由文件以及vue文件
<script src="./lib/vue.js"></script>
<script src="./lib/vue-router.js"></script>
注意:引入时需要注意顺序,路由是基于vue存在的
创建路由对象:
const luyou = new VueRouter({
routes:[
{path:"/t",component:home},
{path:"/n",component:help}
]
})
属性routes:路由规则集(路由表),内部为一个路由规则数组
路由案例
<body>
<div id="a">
<router-link to="/t">点我显示主页</router-link>
<router-link to="/n">点我显示帮助</router-link>
<router-view></router-view>
<home></home>
</div>
<!-- 注意router-view也可以写成自闭标签,自闭标签只能显示该自闭标签的视图,以下再有组件或视图则无法显示 -->
</body>
<script src="./lib/vue.js"></script>
<script src="./lib/vue-router.js"></script>
<script>
var home={template:"<h1>我是主页</h1>"}
var help={template:"<h1>我是帮助</h1>"}
/* 创建路由对象 */
const luyou = new VueRouter({
routes:[
{path:"/t",component:home},
{path:"/n",component:help}
]
//注意创建路由实例,定义了路由规则,路由此路径必须有/
})
new Vue({
el:"#a",
router:luyou,
components:{
home,help
}
//此组件在vue实例中也可以使用
})
</script>
注意:
- 上面的router-view可以写成自闭标签,那么之后如果在有router-view或组件则不生效
- 使用路由必须创建路由对象,在路由对象里定义路由规则,路由规则内的path必须携带斜杠以表示他是一个路径,上面的router-link内的to属性可以有/也可以没有
- 路由必须使用在vue渲染区处
- router-link就像一个a标签一样,你点击了此处就会默认跳转到某一路径
vue-router
前言
- vue的一个插件库,专门用来实现SPA单页面应用
- 在vue中,我们可以通过vue-router路由管理页面之间的关系
- vue router是vue.js的官方路由。他与vue.js核心深度集成,让vue.js构建单页面应用轻而易举
- 核心:改变url,但是页面不进行整体刷新
单页面应用与多页面应用
单页面应用 | 多页面应用 | |
组成 | 一个外壳页面和多个页面片段组成 | 多个完整页面构成 |
资源共用 | 共有,只需要在外壳部分加载 | 不共用,每个页面都需要加载 |
刷新方式 | 页面局部刷新或更改 | 整页刷新 |
用户体验 | 页面片段间的切换快,用户体验良好 | 页面切换加载缓慢,流畅度不够,用户体验比较差 |
转场动画 | 容易实现 | 无法实现 |
数据传递 | 容易 | 依赖url传参、或者cookie、localStorage等 |
vue-router的使用
在vue中引入路由
安装路由:npm install --save vue-router
配置独立的路由文件
在src文件下新建一个文件夹router里面建一个index.js文件作为路由的配置文件
// 路由配置文件index.js
//引入路由
import {createRouter,createWebHashHistory} from "vue-router"
//引入组件
import Home from '../components/Home.vue'
//配置路由规则(路由表)
const routes=[
{path:"/",component:Home},
//异步加载方式:如果页面没有被显示出来component后面的代码是不会执行的,不会执行的话就节省了内存空间(路由懒加载)
{path:"/about",component:()=>import('../components/About.vue')}
]
// 创建路由器
const router=createRouter({
history:createWebHashHistory(),
routes
})
//导出路由器
export default router
//main.js文件内
import { createApp } from 'vue'
import App from './App.vue'
//引入路由
import router from './router/index.js'
const app=createApp(App)
//注册全局路由
app.use(router).mount('#app')
<template>
<!-- 路由跳转按钮 -->
<router-link to="/">home页面</router-link> |
<router-link to="/about">about页面</router-link>
<!-- 路由导航视图 -->
<router-view></router-view>
</template>
<script>
export default {
name: 'App'
}
</script>
路由静态加载与懒加载
懒加载:用到时才会加载对应的组件,这样可以使项目的运行变得高效
//静态导入
import Home from "../components/Home.vue"
//动态导入
const About=()=>import("../components/About.vue")
const routes=[
//静态加载
{path:"/",component:Home},
//路由懒加载
{path:"/about",component:About},
]
带参数的路由匹配
前言:路由是管理页面之间的跳转关系的,在跳转的过程中,页面与页面之间也需要传递参数
最终效果:随着路由传递的参数改变,导致同一组件内容的改变
const routes=[
//路由传递参数,用:name作为占位符
{path:"/about/:name",component:()=>import('../components/About.vue')},
]
<template>
<!-- app组件内 -->
<router-link to="/about/网易">网易页面</router-link>
<router-link to="/about/京东">京东页面</router-link>
<!-- 路由导航视图 -->
<router-view></router-view>
</template>
<template>
<div class="about">
<!-- about组件内 -->
<!-- 获取路由中传递的name参数 -->
<p>{{$route.params.name}}</p>
</div>
</template>
路由正则
const routes = [
//路由正则(传递的name参数必须为数字)
{ path: "/about/:name(\\d+)", component: () => import('../components/About.vue') },
//正则匹配about页面,表示后面的参数可以有多个(+表示一个或多个;*表示0个或多个;?表示一个或多个)
{ path: "/about/:name+", component: () => import('../components/About.vue') },
//正则匹配,若找不到以上对应的路由则走该路由
{ path: "/:path(.*)", component: () => import('../components/Error.vue') },
]
<template>
<!-- app组件内 -->
<router-link to="/about/网页">网易页面</router-link><!-- 因为正则匹配点击之后显示Error页面 -->
<router-link to="/about/666">666页面</router-link>
<router-link to="/about/a/b">多参数页面</router-link><!-- [ "a", "b" ] -->
<router-link to="/notfound">找不到页面</router-link>
<!-- 路由导航视图 -->
<router-view></router-view>
</template>
<template>
<div class="about">
<!-- about组件内 -->
<!-- 获取路由中传递的name参数 -->
<p>{{$route.params.name}}</p>
</div>
</template>
<template>
<!-- Error组件内 -->
<h1>404</h1>
</template>
路由嵌套
前言:一个程序的ui是由多个嵌套组件组成,在这种情况下,url的片段通常对应于特定的嵌套组件结构,通过路由嵌套可以表达这种组件的嵌套关系
路由嵌套架构版
<body>
<div id="a">
<router-link to="t">home</router-link>
<router-link to="h">help</router-link>
<router-view></router-view>
</div>
<template id="b">
<div>
<h1>我是home组件</h1>
</div>
</template>
<template id="c">
<div>
<router-link to="n">help1</router-link>
<router-link to="m">help2</router-link>
<router-view></router-view>
</div>
</template>
<template id="d">
<div>
<h1>我是help1组件</h1>
</div>
</template>
<template id="e">
<div>
<h1>我是help2组件</h1>
</div>
</template>
</body>
<script src="./lib/vue.js"></script>
<script src="./lib/vue-router.js"></script>
<script>
var home={template:"#b"}
var help={template:"#c"}
var help1={template:"#d"}
var help2={template:"#e"}
new Vue({
el:"#a",
router: new VueRouter({
routes:[
{path:"/",redirect:"/t"},//路由重定向
{path:"/t",component:home},
{path:"/h",component:help,children:[
{path:"/h",redirect:"/n"},
{path:"/n",component:help1},
{path:"/m",component:help2}
]},
]
})
})
</script>
注意:路由里面的children属性为子路由,里面为路由规则数组
理解过程:
访问“/”路径就重定向到“/t”路径,所以在你访问的时候主页面默认就是home组件,结果你点击了help组件,由于其存在子路由,并且我默认在里面设置了重定向到help1组件,所以,当你点击help组件时会默认看到help1组件,点击了help2组件跳到help2,其他的以此类推
路由嵌套项目版
const routes=[
{path:"/",component:()=>import("../components/Home")},
{path:"/about",component:()=>import("../components/About"),
redirect:"/about/second",//路由重定向
children:[
//注意:子路由路径前面不带/,因为自动帮你识别了
{path:"first",component:()=>import("../components/First")},
{path:"second",component:()=>import("../components/Second")}
]
}
]
<template>
<!-- app组件内 -->
<router-link to="/">home</router-link> |
<router-link to="/about">about</router-link>
<router-view></router-view>
</template>
<template>
<div class="about">
<!-- about组件内 -->
<h1>About</h1>
<router-link to="/about/first">first</router-link> |
<router-link to="/about/second">second</router-link>
<router-view></router-view>
</div>
</template>
编程式导航
注意:$router是一个全局路由容器,里面包含着许多路由对象,$route是$router容器中活跃的那个路由对象
普通形式
跳转到特定的组件:this.$router.push("/about")
前进一步:
- this.$router.forward()
- this.$router.go(1)
后退一步:
- this.$router.back()
- this.$router.go(-1)
刷新页面:this.$router.go(0)
注意:go方法内的参数为前进或后退的步数
<script src="../lib/vue.js"></script>
<script src="../lib/vue-router.js"></script>
</head>
<body>
<div id="all">
<!-- 路由跳转 -->
<router-link to="/home">home</router-link>
<router-view></router-view>
<button @click="change">跳到help页面</button>
<button @click="goahead">前进一步</button>
<button @click="goback">后退一步</button>
<button @click="goon">刷新页面</button>
</div>
</body>
<script>
var home={template:"<h1>我是主页</h1>"}
var help={template:"<h1>我是帮助页</h1>"}
const router = new VueRouter({
routes:[
{path:"/home",component:home},
{path:"/help",component:help},
]
})
new Vue({
el:"#all",
methods: {
change(){
//路由跳转——this.router为全局路由对象
this.$router.push("/help")
},
goahead(){
this.$router.forward()
//this.$router.go(1)也可以
},
goback(){
this.$router.back()
//this.$router.go(-1)也可以
},
goon(){
this.$router.go(0)
}
},
router:router,
})
</script>
通过名字进行跳转并携带参数
const routes=[
{path:"/about",component:()=>import('../components/About.vue')},
//路由传递参数,用:name作为占位符
{name:"about",path:"/about/:name",component:()=>import('../components/About.vue')},
]
<template>
<!-- app组件内 -->
<router-view></router-view>
<button @click="pushOn">restful形式传参</button>
<button @click="pushForward">问号拼接形式传参</button>
</template>
<script>
export default {
methods:{
pushOn(){
//根据about名字进行跳转,并携带淘宝参数(对应上面的name)
//http://localhost:8080/#/about/淘宝
this.$router.push({name:"about",params:{name:"淘宝"}})
},
pushForward(){
//http://localhost:8080/#//about?app=58同城
//about路径后面拼接?以及参数(注意这里仅仅是about内的?传参)
this.$router.push({path:"/about",query:{app:"58同城"}})
}
}
}
</script>
<template>
<div class="about">
<!-- about组件内 -->
<h1>about</h1>
<!-- restful形式拼接获取参数 -->
{{$route.params.name}}
<!-- 问号拼接形式获取参数 -->
{{$route.query.app}}
</div>
</template>
替换当前位置
前言:他的作用类似于router-push,唯一不同的是,它在导航时不会向history添加新纪录,正如他的名字所暗示的那样,它仅仅是取代了当前的页面
路由表
const routes=[
{path:"/",component:()=>import('../components/Home.vue')},
{path:"/about",component:()=>import('../components/About.vue')},
]
方式一
<template>
<!-- app组件内 -->
<!-- 替换模式,跳转的路径不会记录在历史记录中 -->
<router-link to="/" replace>home</router-link>
<router-link to="/about" replace>about</router-link>
<router-view></router-view>
</template>
方式二
<template>
<!-- app组件内 -->
<button @click="goHome">home</button>
<button @click="goAbout">about</button>
<router-view></router-view>
</template>
<script>
export default {
methods:{
goHome(){
//替换模式(方式1——replace属性)
this.$router.push({path:"/",replace:true})
},
//替换(方式2——replace方法)
goAbout(){
this.$router.replace("/about")
}
}
}
</script>
命名路由
const routes=[
{path:"/",component:()=>import('../components/Home.vue')},
{name:"about",path:"/about/:name",component:()=>import('../components/About.vue')},
]
<template>
<!-- app组件内 -->
<!-- 根据name来跳转路由并顺便传递参数,注意to后面的语句必须被当成变量 -->
<router-link :to="{name:'about',params:{name:'京东'}}">about</router-link>
<router-view></router-view>
</template>
<template>
<div class="about">
<!-- about组件内 -->
<h1>about</h1>
<!-- restful形式拼接获取参数 -->
{{$route.params.name}}
</div>
</template>
命名视图(厉害)
场景:我们想要同时展示多个视图,这时候命名视图就派上用场了,可以在页面上拥有多个单独命名的视图,而不是一个单独的出口,若route-view没有名字,那么默认为default(一个视图使用一个组件渲染,因此多个视图就用多个组件渲染)
const routes=[
{path:"/num",
components:{
//default代表当访问该num路径对应的路由的话,那么就默认跳到First组件
default:()=>import("../components/First.vue"),
Second:()=>import("../components/Second.vue"),
Third:()=>import("../components/Third.vue")
}}
]
<template>
<!-- app组件内 -->
<router-link to="/num">数字集</router-link>
<!-- 展示default默认的组件 -->
<router-view></router-view>
<!-- 展示Second组件 -->
<router-view name="Second"></router-view>
<!-- 展示Third组件 -->
<router-view name="Third"></router-view>
</template>
路由重定向
通过路径进行重定向
const routes=[
//路由重定向
{path:"/",redirect:"/home"},
{path:"/home",component:()=>import("../components/Home.vue")}
]
通过路由名进行重定向
const routes=[
//通过路由名进行重定向
{path:"/",redirect:{name:"home"}},
{name:"home",path:"/home",component:()=>import("../components/Home.vue")}
]
函数进行重定向
const routes=[
//通过路由名进行重定向
{path:"/",redirect:(to)=>{
//to表示当前路径,里面可以用to进行一些判断
console.log(to);
return{path:"/home"}
}},
{path:"/home",component:()=>import("../components/Home.vue")}
]
别名路径访问
注意:此别名路径不仅能用于重定向,也可以直接访问
const routes=[
//通过路由名进行重定向
{path:"/",redirect:"/building"},
//为该路由起小名为/building
{alias:"/building",path:"/home",component:()=>import("../components/Home.vue")}
]
统一测试
<template>
<router-link to="/">开始页面</router-link>
<router-view></router-view>
</template>
路由组件传参
前言:通常情况下在组件中使用$route会与路由紧密耦合,这就限制了组件的灵活性,因为他只能用于特定的url,但是我们也可以通过props配置来解除这种行为
注意:当props设置为true的时候,那么$route.params将被设置为组件的props
普通情况
const routes=[
//路由组件传参
{path:"/home/:app",component:()=>import("../components/Home.vue"),props:true}
]
<template>
<div class="home">
<!-- 普通获取路由参数 -->
<h1>{{$route.params.app}}</h1>
<!-- 路由组件传参 -->
<h2>{{app}}</h2>
</div>
</template>
<script>
export default {
props:['app']
}
</script>
<template>
<router-link to="/home/前程无忧">路由组件传参</router-link>
<router-view></router-view>
</template>
命名视图下的路由组件传参
const routes=[
//路由组件传参
{path:"/num/:app",components:{
default:()=>import("../components/First.vue"),
Second:()=>import("../components/Second.vue"),
Third:()=>import("../components/Third.vue")
},
//让默认的为true进而开启路由组件传参
props:{default:true,Second:false,Third:false}}
]
<template>
<h1>first内</h1>
<p>{{app}}</p>
</template>
<script>
export default {
props:['app']
}
</script>
<template>
<!-- app.vue内 -->
<router-link to="/num/前程无忧">路由组件传参</router-link>
<router-view></router-view><!-- 这里面可以使用路由组件传参 -->
<router-view name="Second"></router-view>
<router-view name="Third"></router-view>
</template>
路由的模式
Hash模式
我们常用的模式
const router = createRouter({
//哈希模式,通过createWebHashHistory()创建的
history: createWebHashHistory(),
routes
})
注意:
- 他在内部传递的实际url之前使用一个哈希字符“#”,由于这部分url从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。
- 使用Hash模式的话,当浏览器改变url时不会向服务器发送请求,这样就不会刷新我们的页面,此时我们的性能便会提高
HTML5模式
const router = createRouter({
//HTML5模式,通过createWebHistory()创建的
history: createWebHistory(),
routes
})
注意:使用这种历史模式时,url看起来会很正常(没有#号),但是由于我们的应用是一个单页的客户端应用,没有适当的服务器配置,容易报404错误
Hash模式与HTML5模式的主要区别:有无哈希符号#
路由导航守卫
含义:路由导航守卫主要是用来通过跳转或取消的方式守卫导航
理解:就是实际中不可能让你想走那个页面就走那个页面,必须通过判断来决定你可不可以走该页面
全局前置守卫
说明:beforeEach用户的每次请求在访问目标网址之前都会被拦截
注意:该全局路由守卫放到全局路由对象中使用
参数:
- to:用户请求的网址对象
- from:用户请求的来源
- next:请求是否放行
用法:
路由对象.beforeEach((to, from, next) => {
if(条件判断){
return next()
}
})
注意:如果返回值给next()则表示此路由可以放行,当然如果next(false)就会放行失败
//路由导航守卫
//调用路由实例里面的BeforeEach方法
router.beforeEach((to,from,next)=>{
//若去往路径为/则直接放行
if(to.fullPath=="/"){
//请求放行
return next();
}else{
console.log(to);
console.log(from);
alert("请先登录")
}
})
局部路由守卫
const routes=[
{path:"/",component:()=>import("../components/Home.vue")},
{path:"/about",component:()=>import("../components/About.vue"),
//局部路由组件(在进入about组件之前进行判断)
beforeEnter: (to, from, next) => {
//若请求从/来则放行
if(from.fullPath=="/"){
next()
}
}},
]
组件内的路由导航守卫
<template>
<div class="home">
<h1>home</h1>
</div>
</template>
<script>
export default {
data(){
return{
age:12
}
},
beforeRouteEnter(to,from,next){
console.log("路由进入组件之前");
//在里面拿不到this,若想拿到则依赖第三个参数
next((vm)=>{
alert(vm.age)
})
},
beforeRouteUpdate(to,from,next){
console.log("路由更新组件之前");
next()
},
beforeRouteLeave(to,from,next){
console.log("路由离开组件之前");
next()
}
}
</script>