一,两种路由模式
1.1 hash模式(对应HashHistory)
特点:
- 页面监听#号后面的url变化,这种路由模式所有的变化都在前端执行,不会像服务器发送请求。
- 每次hash值变化都会在浏览器的访问历史中增加一个记录。
- hash不会造成404的问题,因为所有的解析都在前端完成
1.2 history模式(对应HTML5History)
特点:
- 是HTML5新推出的功能,比hash url更美观,在浏览器刷新页面时,会真实按照路径发送请求
- 如果发送请求的路径nginx没有匹配到,就会出现404页面
- 改变url:history提供了pushState和replaceState两种方法来记录路由状态,这两种方法只会改变url,不会刷新页面
- 监听url变化:通过onpopstate事件监听history的变化,在点击浏览器的前进或者后退时触发,根据状态信息加载对应的页面内容。
二,router-link
router-link组件的本质就是a标签,他绑定了click事件,然后通过执行对应的VueRouter实例的push()实现的。他使Vue Router可以在不重新加载页面的情况下更改URL,处理URL的生成以及编码。
使用示例:
<router-link :to="{ name: 'detail', params: { appId: '12345' }}">
this.$router.push({ name: 'detail', params: { appId: '12345' }})
二者实现效果一致
三,router-view
router-view组件是一个函数式组件(没有data,没有组件实例),他的主要作用就是路由变化时渲染指定url的组件。他可以放在任何地方,来适应项目中的布局。
使用示例:
支持使用name进行命名。
<router-view class="left" name="left"></router-view>
<router-view class="home"></router-view>
routes: [
{
path: '/',
components: {
default: Home,
// left: left的缩写。与 `<router-view>` 上的 `name` 属性匹配
left,
},
},
],
四,$route
概念:当前路由信息的对象。获取和当前路由相关的信息,route是只读的属性,可以通过watch来监听路由的变化。
常用属性:
- fullPath: "" // 当前路由完整路径(包含查询参数和hash)
- hash: "" // 当前路由的 hash 值 (锚点)
- meta: {} // 路由文件中自赋值的meta信息
- name: "" // 当前路由名称
- path: "" // 当前路由路径
- params: {} // 包含了动态片段和全匹配片段就是一个空对象。
- query: {} // 表示 URL 查询参数。跟随在路径后用'?'带的参数
五,$router
概念:vueRouter的实例对象。他是一个全局路由对象,可以通过this.$router访问路由或路由提供的方法。
常用属性/方法:
- router.push - 路由跳转
- router.replace - 替换当前路由页面(这样跳转不会产生历史记录)
- router.go - 跳转到具体某个历史记录
- router.back - 历史记录向回退
- router.forward - 历史记录向前进
- router.hasRoute() - 判断路由是否存在
- router.getRoutes() - 获取所有路由组成的数组
- router.addRoute($options) - 添加路由
- router.removeRoute($name) - 删除路由
- router.beforeEach((to, from, next) - 全局路由前置守卫
- router.beforeResolve((to, from, next) - 全局路由解析守卫
- router.afterEach((to, from) - 全局路由后置守卫
- ... ...
六,路由守卫
6.1 全局守卫
- router.beforeEach(to, from, next)- 全局前置守卫。在路由跳转前触发,类似于拦截器,主要用来做登陆验证
- router.afterEach(to, from)- 全局后置守卫。在路由跳转完成后触发(因此没有next)
- router.beforeResolve(to, from, next)- 全局解析守卫。每次导航都会触发,他是在所有组件内守卫beforeEach和组件内beforeRouteEnter之后、afterEach之前调用。可以用来获取数据和执行操作等。
6.2 独享路由守卫
理解:直接在路由配置上定义,但是它只在进入路由时触发,不会在 params、query 或 hash 改变时触发。
示例:
const routes = [
{
path: '/detail/:id',
component: appDetail,
// 直接在路由配置中定义守卫
beforeEnter: (to, from, next) => {
next()
},
},
]
beforeEnter可以接受一个函数数组,用于路由守卫重用,例如:
const routes = [
{
path: '/detail/:id',
component: appDetail,
beforeEnter: [removeQueryParams, removeHash],
}
]
// 守卫函数1
function removeQueryParams(to) {
if (Object.keys(to.query).length)
return { path: to.path, query: {}, hash: to.hash }
}
// 守卫函数2
function removeHash(to) {
if (to.hash) return { path: to.path, query: to.query, hash: '' }
}
6.3 组件内的守卫
概念:组件内的路由守卫就像组件各个生命周期的钩子函数。
- beforeRouteEnter(to,from, next) -- 进入之前。在渲染该组件的对应路由被验证前调用(此时组件实例还没有被创建,不能访问this)
- beforeRouteUpdate(to,from, next) -- 路由变化时。在当前路由改变,但是该组件被复用时调用(触发这个的时候,组件已经挂载好了,可以访问this)
- beforeRouteLeave(to,from, next) -- 离开后。在导航离开渲染该组件的对应路由时调用(可以访问this)
6.4 路由守卫触发顺序
页面加载时:
1,全局前置守卫 - beforeEach
2,A组件独享守卫 - beforeEnter
3,A组件路由守卫 - beforeRouteEnter
4,全局解析守卫 - beforeResolve
5,全局后置守卫 - afterEach
[6,组件的挂载:beforeCreate => created => beforeMount]
7,A组件路由守卫 beforeRouteEnter 中的 next回调(此时能够获取到组件实例 vm)
[8,A组件完成挂载:mounted]
点击切换路由时:
1,A组件守卫 - beforeRouteLeave
2,全局前置守卫 - beforeEach
[3,在重用的组件里调用 beforeRouteUpdate ]
4,B组件独享守卫 - beforeEnter
5,B组件路由守卫 - beforeRouteEnter
6,全局解析守卫 - beforeResolve
7,全局后置守卫 - afterEach
[8,B组件挂载:beforeMount]
9,B组件路由守卫 beforeRouteEnter 中的 next回调
10,A组件beforeDestory
11,A组件destory
12,[B组件完成挂载mounted]
路由更新时:
触发beforeRouteUpdate
七,异步获取数据
异步调用接口获取数据,通常有两种情况:
1,在导航完成之后调用接口(通过created或mounted)
2,在导航完成之前调用接口,然后调用导航的next(vm => vm.setData())(通过beforeRouteEnter)
示例:
// 导航完成之后
created() {
const id = this.$route.params.id; // 从路由获取参数
getList().then((response) => {
if (response.code === 10000) {
// ...
}
})
},
// 导航完成之前
beforeRouteEnter(to, from, next) {
const id = to.params.id; // 从路由参数获取参数
getList(id, (err, post) => { // 成功的回调
next(vm => vm.setData(err, post)); // next方法接受的vm参数调setData传数据
})
},
八,滚动scrollBehavior
概念:vue-router支持页面滚动效果实现,仅需提供一个scrollBehavior方法即可(在创建VueRoute对象时)。
使用方式:scrollBehavior(to, from, savedPosition) { return 期望滚动到的位置 }
注意:
- 返回falsy和空对象则不滚动。
- savedPosition是在按下浏览器的前进、后退按钮时触发,返回一个位置对象
示例:
const router = createRouter({
history: createWebHashHistory(),
routes: [...],
scrollBehavior (to, from, savedPosition) {
// 方式1:指定位置信息。滚动到顶部
return { top: 0 };
// 方式2:相对指定CSS选择器的偏移位置
return { el: "#main", top: 10 };
// 方式3:相对指定DOM元素的偏移位置
let dom = document.getElementById('main');
return { el: dom, left: 10 };
// 方式4:滚动到锚点
if (to.hash) {
return { el: to.hash };
}
// 方式5:延迟滚动 - 返回一个promise对象,在resolve中传参位置信息
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ top: 10, left: 20});
}, 500)
})
}
})
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
},
})
九,keep-alive
概念:keep-alive是vue的一个内置组件,主要作用是缓存组件在内存中,防止重复渲染dom。
常用属性:
- include - 字符串或正则。匹配到的name会被缓存
- exclude - 字符串或正则。匹配到的name不会被缓存
- max - 数字。最多可以缓存多少个组件实例
路由搭配应用:
可以在路由的元信息meta中设置keepAlive属性,来判断是否需要缓存,例如:
{
path: 'list',
name: 'itemList',
component: () => import '@/pages/item/list',
meta: {
keepAlive: true, // 保存当前路由是否需要缓存
title: '列表页'
}
}
<!-- 需要被缓存的组件 -->
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!-- 不需要缓存的组件 -->
<router-view v-if="!$route.meta.keepAlive"></router-view>
删除keep-alive中的缓存:
1,首先对router-view标签设置ref属性(例如:<router-view ref="routerView"></router-view>)
2,通过delete删除ref.$vnode.parent.componentInstance.cache属性(例如:
delete this.$refs.routerView.$vnode.parent.componentInstance.cache)