前端路由的核心是什么呢?
改变URL,但是页面不进行整体的刷新。
如何实现呢?
URL的hash
- URL的hash也就是锚点(#), 本质上是改变window.location的href属性.
- 我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新
location.hash='foo' → http://localhost:8080/#foo
HTML5的history模式
history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面.
- history.pushState({data}, ‘title’, ‘url’) 栈结构—先进后出(出栈/返回上一步:history.back())
参数第一位:传数据
参数第二位:设置标题
参数第三位:地址
history.pushState({}, '', 'home') → http://localhost:8080/home (可以使用返回箭头)
- history.replaceState({data},“title”,“url”)
history.replaceState({},"","abut") → http://localhost:8080/abut (不能使用返回箭头,被替换)
- history.go()
history.go(-1) === history.back() 退栈
history.go(2) 进栈2个
补充说明: 上面只演示了三个方法 因为
history.back() 等价于 history.go(-1)
history.forward() 则等价于 history.go(1)
这三个接口等同于浏览器界面的前进后退。
安装和使用vue-router
安装vue-router
npm install vue-router --save
在src目录里新建 router文件夹并创建index.js配置router
- 引入组件
import VueRouter from 'vue-router'
import Vue from 'vue'
- 通过vue.use() 安装插件
Vue.use(VueRouter)
- 创建router对象
const router = new VueRouter({
//配置路由和组件直接的应用关系
routes
})
- 将routers配置抽离
const routes = [
…
] - 将router对象挂载到vue实例mian.js中
export default router
6. 创建路由组件并引入到路由配置页面配置组件联系
import Home from '../components/Home'
import Abut from '../components/Abut'
const routes = [
//设置默认页面
{
path:'',
component:Home
},
{
path:'/home',
component:Home
},
{
path:'/abut',
component:Abut
}
]
- 在APP.vue中使用路由
使用路由: 通过 router-link 和 router-view
路由的默认路径–redirect重定向
const routes = [
{
path:'/',
redirect:Home
},
]
设置路径模式—一般使用HTML5的history模式
const router = new VueRouter({
routes,
mode:'history'
})
配置文件完整代码
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../components/Home'
import Abut from '../components/Abut'
Vue.use(VueRouter)
const routes = [
{
path:'/',
redirect:Home
},
{
path:'/home',
component:Home
},
{
path:'/abut',
component:Abut
}
]
const router = new VueRouter({
routes,
mode:'history'
})
export default router
router-link属性
- to:用于指定跳转的路径。
- tag: tag可以指定router-link之后渲染成什么组件, 比如上面的代码会被渲染成一个li元素, 而不是a。
- replace: replace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中。
- active-class: 当router-link对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称。
<template>
<div id="app">
<router-link to="/home" tag="li" active-class="active" replace>首页</router-link>
<router-link to="/abut" active-class="active" replace>关于</router-link>
<router-view></router-view>
</div>
</template>
修改linkActiveClass
const router = new VueRouter({
routes,
mode:'history',
linkActiveClass:'active'
})
代码实现跳转
<template>
<div id="app">
<button @click="homeClick">首页</button>
<button @click="abutClick">关于</button>
<router-view></router-view>
</div>
</template>
<script>
export default {
methods: {
homeClick() {
this.$router.push('/home')
//不需要返回功能
//this.$router.replace('/home')
},
abutClick() {
this.$router.push('/abut')
}
}
}
</script>
解决多次点击报错问题:在main.js中添加一下代码
import Router from 'vue-router'
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
动态路由
传递参数的方式
传递参数主要有两种类型: params/query和JavaScript传参
- 方式一:params传参
{
path:'/home/:id',
component:Home
},
<router-link :to="/home/+1234">首页</router-link>
<script>
data() {
return {
id: 1234
}
},
</script>
<h2>我是首页的参数{{$route.params.id}}</h2>
- 方式一:query传参
在router-link中进行
<router-link :to="{
path: '/abut',
query: {
name: 'zhangsan',
age: 18,
height: 160
}
}">关于</router-link>
//获取参数
<h2>{{$route.query}}</h2>
- 传递参数方式二: JavaScript代码
获取参数通过$route对象获取
备注: - this.$router 指VueRouter实例,想要导航到不同URL,则使用router.push方法
- this.$route 指当前router跳转对象(当前活跃对象)里面可以获取name、path、query、params等
嵌套路由
嵌套路由是一个很常见的功能
比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容.一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件.
实现嵌套路由有两个步骤:
创建对应的子组件, 并且在路由映射中配置对应的子路由.
在组件内部使用router-view标签.
导航守卫
- vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.
- vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发.
前置钩子(hook)beforEach():跳转之前执行
router.beforeEach((to, from, next) => {
next(), //下一步
//...
})
导航钩子的三个参数解析:
to: 即将要进入的目标的路由对象.
from: 当前导航即将要离开的路由对象.
next: 调用该方法后, 才能进入下一个钩子.
例:给每个页面设置title
首先, 我们可以在钩子当中定义一些标题, 可以利用meta来定义。
其次, 利用导航守卫,修改我们的标题。
//如果首次进入的title 为undefined使用matched
window.document.title = to.matched[0].meta.title
后置钩子(hook)afterEach():跳转之后执行
router.afterEach((to, from) => {
//... 这里不需要调用next()
})
- 补充一:如果是后置钩子, 也就是afterEach, 不需要主动调用next()函数.
- 补充二: 上面我们使用的导航守卫,被称之为全局守卫.
- 路由独享的守卫.
- 组件内的守卫.
更多内容, 可以查看官网进行学习: 官网地址
keep-alive
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
它们有两个非常重要的属性:
include - 字符串或正则表达,只有匹配的组件会被缓存
exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存:
<keep-alive>
<router-view include='home'></router-view>
</keep-alive>
通过create声明周期函数来验证
当使用keep-alive组件时可调用activated() 和 deactivated()方法
//活跃时
activated() {
console.log('activivated');
},
//不活跃时(离开时)
deactivated() {
console.log('deactivated');
},
引入:路由嵌套时使用keep-alive效果失效问题以home页面为例
解决思路:定义变量path到data值:
export default {
name:'home',
data() {
return {
path: '/home'
}
}
}
当home处于活跃时设置地址
activated() {
this.$router.push(this.path)
},
使用组件守卫保存当前要离开时的页面路径
beforeRouteLeave (to, from, next) {
this.path = this.$route.path;
next()
}
拓展:解决路由js绑定地址多次报错问题:
复制以下代码到main.js中
import Router from 'vue-router'
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}