vue2-router 总结
前言 import Home from ‘…/Home.vue’ 这行代码中的三个点“…” 是省略号的意思。
一、router 安装
1. 直接在脚手架中勾选
新手使用 router 的时候,建议直接在使用脚手架创建 vue2 项目的时候,直接勾选,这样不容易安装错误对应的版本,导致一些错误。
2. 单独安装 ( vue2 ----> router3 )
npm i vue-router@3.2.0
二、router配置
1. router文件配置
在 src 文件夹下面创建一个名为 router 的文件夹;在 router 文件夹中创建一个 index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '.../Home.vue'
Vue.use(VueRouter)
// 路由表, 路由就是在这里配置,后面会详细讲解
const routes=[
{
path:'/home',
component:Home
}
]
// 创建一个路由实例
const router =new VueRouter({
// hash 表示 hash 模式 history 表示 history 模式
// 二者区别的表现在于地址栏有没有 #
mode:'hash',
routes
})
// 导出
export default router
2. 在 main.js 中的配置
在脚手架创建的项目中的入口文件(main.js)中导入,然后集成
import Vue from 'vue'
// 引入 router
import router from '...router/index.js'
// 引入根组件
import App from '..../App.vue'
new Vue({
router:router,
render:h=>h(App)
}).$mount("#app")
三、路由表的具体配置-routes
1. 普通路由配置
// 引入 对应的组件
import Home from '.../Home.vue'
import Center from '.../Center.vue'
const routes=[
{
// 基本的路由 配置 只需要这样两个属性即可
path:'/home',
component:Home
},
{
path:'/center',
component:Center
},
]
1-1. 对应的声明式导航
当我们点击 router-link
的时候 ,
对应路径的组件会被加载到 <router-view></router-view>
// 声明式导航一
<router-link to="/home">首页</router-link>
<router-link to="/center">个人中心</router-link>
// 声明式导航二
<router-link :to="{path:'/home'}">首页</router-link>
<router-link :to="{path:'/center'}">个人中心</router-link>
// 这里是对应的组件的显示的标签
<router-view></router-view>
1-2. 对应的编程式导航
<button @click="onGoHome">首页</button>
<button @click="onGoCenter">个人中心</button>
// 这里是对应的组件的显示的标签
<router-view></router-view>
<script>
export default {
methods:{
onGoHome(){
// $router 代表的就是 new VueRouter()实例
// 这里就是 编程式导航的路由跳转
// this.$router.push('/home') // 这里是第一种写法
this.$router.push({path:'/home'}) // 也可以传入一个对象 第二种写法
},
onGoCenter(){
// 这里就是 编程式导航的路由跳转
// this.$router.push('/center') // 这里是第一种写法
this.$router.push({path:'/center'}) // 也可以传入一个对象 第二种写法
}
}
}
</script>
2. 命名路由
// 引入 对应的组件
import Home from '.../Home.vue'
import Center from '.../Center.vue'
const routes=[
{
path:'/home',
name:'home', // 给路由添加一个 name 属性 就是命名路由了
component:Home
},
{
path:'/center',
name:'center', // 给路由添加一个 name 属性 就是命名路由了
component:Center
},
]
2-1. 对应的声明式导航
// 声明式导航
<router-link :to="{name:'home'}">首页</router-link>
<router-link :to="{name:'center'}">个人中心</router-link>
// 这里是对应的组件的显示的标签
<router-view></router-view>
2-2. 对应的编程式导航
<button @click="onGoHome">首页</button>
<button @click="onGoCenter">个人中心</button>
// 这里是对应的组件的显示的标签
<router-view></router-view>
<script>
export default {
methods:{
onGoHome(){
this.$router.push({name:'home'})
},
onGoCenter(){
this.$router.push({name:'center'})
}
}
}
</script>
3. 动态路由
// 引入 对应的组件
import Home from '.../Home.vue'
import Center from '.../Center.vue'
import Info from '.../Info.vue'
const routes=[
{
// 动态路由就是在路径后面添加 /:参数名 参数名可以随意取
path:'/home/:id',
name:'home',
component:Home
},
{
// 动态路由就是在路径后面添加 /:参数名 参数名可以随意取
path:'/center/:username',
name:'center',
component:Center
},
{
// 动态路由就是在路径后面添加 /:参数名 参数名可以随意取 可以书写多个动态的
path:'/info/:id/:uid',
name:'info',
component:Info
},
]
3-1. 对应的声明式导航
3-1-1. 对应的声明式导航传参的动态路由-(直接拼接的模式)
// 直接拼接一个 (/参数即可)
<router-link to="/home/123">首页</router-link>
// 这里是对应的组件的显示的标签
<router-view></router-view>
获取对应的参数值:
<script>
export default {
created(){
console.log(this.$route.params.id) // 获取对应的 id 的值
}
}
</script>
3-1-2. 对应的声明式导航传参的动态路由-(传递一个对象的模式)-query
<router-link :to="{path:'/home',query:{id:123}">首页</router-link>
// 这里是对应的组件的显示的标签
<router-view></router-view>
获取对应的参数值:
<script>
export default {
created(){
console.log(this.$route.query.id) // 获取对应的 username 的值
}
}
</script>
3-2. 对应的编程式导航
// 这里是对应的组件的显示的标签
<router-view></router-view>
<button @click="onGoHome">首页</button>
<script>
export default {
methods:{
onGoHome(){
// 第一种写法-----111
// this.$router.push('/home/'+123) // '123' 也可以是一个变量
// 第二种写法-----222
this.$router.push({path:'/home',query:{id:123}})
}
}
}
</script>
获取对应的参数值:
<script>
export default {
created(){
// 获取第一种写法的参数-----111
// console.log(this.$route.params.id)
// 获取第二种写法的参数-----222
console.log(this.$route.query.id)
}
}
</script>
4. 嵌套路由
// 引入 对应的组件
import Home from '.../Home.vue'
import Center from '.../Center.vue'
// 引入对应的组件
import Child1 from '.../Child1.vue'
import Child2 from '.../Child2.vue'
const routes=[
{
path:'/home',
component:Home,
// 嵌套路由就是 给路由添加一个 children 属性,属性值是一个数组,数组中在书写路由的配置即可
children:[
{
path:'child1', // 注意这儿的书写
component:Child1
},
{
path:'child2', // 注意这儿的书写
component:Child2
}
]
},
{
path:'/center',
component:Center
},
]
4-1. 对应的声明式导航
// 以下代码 应该写在 home 组件中 对应的层级关系才正确
<router-link to="/home/child1">首页</router-link>
// 这里是对应的组件的显示的标签
<router-view></router-view>
4-2. 对应的编程式导航
// 这里是对应的组件的显示的标签
<router-view></router-view>
<button @click="onGoHomeChild1">首页/child1</button>
<script>
export default {
methods:{
onGoHomeChild1(){
// 第一种写法
// this.$router.push('/home/child1')
// 第二种写法
this.$router.push({path:'/home/child1'})
}
}
}
</script>
5. 命名视图
何为命名视图:命名视图就是一个 path 对应多个 component
// 引入 对应的组件
import Home from '.../Home.vue'
import Center from '.../Center.vue'
import Slide from '.../Slide.vue'
const routes=[
{
path:'/home',
//这里就是命名视图,当路径是 /home 的时候,会显示下面的两个组件,需要页面做一些设置
components:{
default:Home,
slider:Slide
}
},
{
path:'/center',
component:Center
},
]
5-1. 对应的声明式导航
<router-link to="/home">首页</router-link>
// 这里是对应的组件的显示的标签
<router-view></router-view> // 这个会加载 components 中的 default 的属性值
<router-view name="slider"></router-view> // 这个会加载 components 中的 slider 的属性值
5-2. 对应的编程式导航
// 这里是对应的组件的显示的标签
<router-view></router-view> // 这个会加载 components 中的 default 的属性值
<router-view name="slider"></router-view> // 这个会加载 components 中的 slider 的属性值
<button @click="onGoHomeChild1">首页/嵌套路由</button>
<script>
export default {
methods:{
onGoHomeChild1(){
// 第一种写法
// this.$router.push('/home/child1')
// 第二种写法
this.$router.push({path:'/home/child1'})
}
}
}
</script>
6. 路由重定向
何为路由重定向:就是在匹配不到对应的路径的时候,就跳转到指定的路径;路由是从上往下匹配的,重定向一般写在最后面;
下面展示了:路由重定向,嵌套路由的重定向
// 引入 对应的组件
import Home from '.../Home.vue'
import Center from '.../Center.vue'
const routes=[
{
// 基本的路由 配置 只需要这样两个属性即可
path:'/home',
component:Home
children:[
{
path:'child1', // 注意这儿的书写
component:Child1
},
{
path:'child2', // 注意这儿的书写
component:Child2
},
{
// 嵌套组件的路由重定向
path:'/home',
redirect:'/home/child1'
}
]
},
{
path:'/center',
component:Center
},
{
// 在上面的路由都不匹配的时候,就重定向到 /home 然后加载对应的组件
path:'*',
redirect:'/home'
}
]
7. 路由懒加载
何为路由懒加载:就是在打开页面的时候,只加载,页面显示的模块。
// 引入 对应的组件
import Home from '.../Home.vue'
import Center from '.../Center.vue'
const routes=[
{
// 基本的路由 配置 只需要这样两个属性即可
path:'/home',
component:()=>import('.../Home.vue') // 按需加载模块,这就是懒加载
},
{
path:'/center',
component:()=>import('.../Center.vue') // 按需加载模块,这就是懒加载
},
]
8. 路由元信息
import Home from '.../Home'
const routes=[
{
path:'/home',
component:Home,
// meta 里面的信息就是路由元信息
// 路由元信息中可以包含 图标 ,label
meta:{
isAuthentication:true,
}
}
]
四、路由的传参的三种方式
4-1. 声明式导航路由传参的三种方式
第一种:动态路由传参-刷新不会丢失参数
const routes=[
{
path:'/detail/:id',
name:'detail',
component:Detail
}
]
声明式导航传参
// 直接拼接即可
<router-link to="/detail/123">详情页</routerlink>
<router-view></router-view>
<router-link :to="{name:'detail',params:{id:123}}">详情页</routerlink>
<router-view></router-view>
<router-link :to="{name:'detail',query:{id:123}}">详情页</routerlink>
<router-view></router-view>
编程式导航传参
<button @click="OnGoDetail">
详情页
</button>
<script>
methods:{
OnGoDetail(){
// 编程式导航的第一种写法,直接拼接参数
// this.$router.push("/detail/123")
// this.$router.push("/detail/"+变量名)
// 第二种写法
// this.$router.push({name:'detail',params:{id:123}})
// 第三种写法
this.$router.push({name:'detail',query:{id:123}})
}
}
</script>
第二种参方式-query-刷新不会丢失参数
const routes=[
{
path:'/detail', // 注意这里的变化 和第一种有区别
name:'detail',
component:Detail
}
]
对应的声明式导航
<router-link :to="{name:'detail',query:{id:123}}">详情页</routerlink>
<router-view></router-view>
对应的编程式导航
<button @click="OnGoDetail">
详情页
</button>
<script>
methods:{
OnGoDetail(){
// 第三种写法
this.$router.push({name:'detail',query:{id:123}})
}
}
</script>
第三种传参方式-params-刷新会丢失参数
const routes=[
{
path:'/detail', // 注意这里的变化 和第一种有区别
name:'detail',
component:Detail
}
]
对应的声明式导航
<router-link :to="{name:'detail',params:{id:123}}">详情页</routerlink>
<router-view></router-view>
对应的编程式导航
<button @click="OnGoDetail">
详情页
</button>
<script>
methods:{
OnGoDetail(){
// 第二种写法
this.$router.push({name:'detail',params:{id:123}})
}
}
</script>
总结
-
使用动态路由传递参数:直接拼接,query,name配合params 都可以,都不会丢失参数。
-
第二,三种传参方式:定义路由规则的时候,没有配置动态路由,那么只能query传参和params传参,params传递的参数看不到,安全性好,但是刷新数据会丢失;但是query传递参数是拼接在链接之后,所以刷新之后不会丢失,这种场景就是和需要分享的链接,可以保证拿到链接的人能看到数据和分享的人一样。
五、路由组件传参-第四种传参方式
const routes=[
{
path:'/home/:id',
component:Home,
props:true // 注意这样一行代码
}
]
// 对应的声明式导航一
<router-link to="/home/123">info</router-link>
// 对应的声明式导航二
<router-link :to="{name:'home',params:{id:123}}">首页</router-link>
// 这里对应的编程式导航略去了,和之前那些一样
获取对应的参数:
<script>
export default {
props:['id']
created(){
console.log(this.id)
}
}
</script>
六、$route 与 $router
1. 二者区别
$route
------> 表示当前活跃的路由对象 ,就是地址栏对应的路径的路由对象
$router
------> 表示整个路由的实例对象,就是 router 文件夹下面的 index.js 文件中 使用 new VueRouter() 出来的那个 router
2. $router详解
this.$router.push()
// 编程式导航中使用
// 这个函数实现的跳转可以回退,具有历史记录
this.$router.push('/login')
this.$router.replace()
// 编程式导航使用
// 这个函数实现的跳转不会保留历史,不能回退
this.$router.replace('/login')
this.$router.go()
this.$router.back()
his.$router.forward()
// 这个函数有一个参数,正数表示前进一步,负数表示后退一步
// 前进一步
this.$router.go(1)
// 后退一步
this.$router.go(-1)
// 后退一步 相当于 go(-1)
this.$router.back()
// 前进一步,相当于 go(1)
this.$router.forward()
七、路由守卫
守卫函数中的参数:
to
: 即将要进入的目标。
from
: 当前导航正要离开的路由。
next
:next 是一个函数,next() 执行下一个钩子;next( false ) 表示中断执行;
next( ‘/login’ ) 里面的参数可以是路由传参的参数设置一样。
next( ‘/login’ ) next( { path :’ /name ’ } ) next( { path :’ /name ', query : { id : 123 } } )
1. 全局守卫
全局前置守卫:
router.beforeEach((to,from,next)=>{
// 在这里的面鉴权
})
1. 路由鉴权的第一种方式
- 这种方式是通过路由白名单来实现的;路由白名单就是一个数组,将不需要鉴权的path放进去,在beforeEach触发的时候,判断一下是不是在数组中,在数组中直接放行即可;不在数组中的,就是需要鉴权的。
// 在src 目录下 新建一个 permission.js
// 引入 路由表文件 router/index.js
import router from '.../router'
router.beforeEach((to,from,next)=>{
const routerArr=['/login','/regist','/home']
if(routerArr.indexOf(to.fullPath) !== -1){
// 直接放行
next()
return
}
let token = localStorage.getItem("TOKEN")
if(token){
// 直接放行
next()
}else{
// 否则跳转至 登录界面
next('/login') // next 中支持 字符串参数,对象参数,参数+传值
}
})
// 使用 在 main.js 文件中引入
import './permission.js'
new Vue({
router,
render:h=>h(App)
}).$mount("#app")
// 在src 目录下 新建一个 permission.js
// 引入 路由表文件 router/index.js
import router from '.../router'
router.beforeEach((to,from,next)=>{
const routerArr=['/login','/regist','/home']
// Array.includes() 可以用来判断数组中是否包含指定的值
if(routerArr.includes(to.fullPath)){
// 直接放行
next()
return
}
let token = localStorage.getItem("TOKEN")
if(token){
// 直接放行
next()
}else{
// 否则跳转至 登录界面
next('/login') // next 中支持 字符串参数,对象参数,参数+传值
}
})
// 使用 在 main.js 文件中引入
import './permission.js'
new Vue({
router,
render:h=>h(App)
}).$mount("#app")
2. 路由鉴权的第二种方式
- 第二种路由鉴权的方式,使用的是元信息鉴权
const routes=[
{
path:'/main',
component:Main,
meta:{
isAuthentication:true,
}
}
]
// 在src 目录下 新建一个 permission.js
// 引入 路由表文件 router/index.js
import router from '.../router'
router.beforeEach((to,from,next)=>{
// matched 是一个数组
if(to.matched.some(item=>item.meta.isAuthentication)){
// 直接放行
next()
return
}
let token = localStorage.getItem("TOKEN")
if(token){
// 直接放行
next()
}else{
// 否则跳转至 登录界面
next('/login') // next 中支持 字符串参数,对象参数,参数+传值
}
})
// 使用 在 main.js 文件中引入
import './permission.js'
new Vue({
router,
render:h=>h(App)
}).$mount("#app")
全局解析守卫:
router.beforeResolve((to)=>{
// 未完待续
})
全局后置守卫:
router.afterEach((to,from)=>{
// 未完待续
})
2. 独享守卫
const routes=[
{
path:'/home/:id',
component:Home,
props:true // 注意这样一行代码
beforeEnter:(to,from,next)=>{
// 和全局守卫的使用一样
}
}
]
3. 组件内守卫
// 未完待续
八、路由的 hash 模式和 history 模式
初始化路由的时候,需要传入一个对象,包含mode,routes
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes=[
{
path:'/home',
component:Home
}
]
const router=new VueRouter({
mode:'hash' // 这个表示路由的 hash 模式
// mode:'history' // 这个表示路由的 history 模式
routes
})
8-1. hash 与 history 的区别
8-1-1. 地址栏表现不一样:
hash 模式地址栏会出现一个 # ;history 模式不会出现,和请求服务器的 API 的地址一样。
8-1-2. 底层原理不一样:
hash模式使用的是 location.hash 实现的:
- hash 将井号
#
拼接在真实 URL 后面的模式。当井号#
后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发hashchange
事件
history 使用的是 html5 的history对象实现的:
- 用户点击浏览器的前进和后退操作,操作保存在history中的。
- history 的
pushState()
和replaceState()
方法
hash的优缺点:
- 优点:浏览器兼容性较好,连 IE8 都支持
- 缺点:路径在井号
#
的后面,比较丑
history的优缺点:
- 优点:路径比较正规,没有井号
#
- 缺点:兼容性不如 hash,且需要服务端支持,否则一刷新页面就404了
九、@/ 代表的意思
@/ === /src // 这个应该看的懂了
// 这个@ 是可以改变的 需要去webpack中配置