Vue
是一个单页面应用程序
框架,所有功能都在一个html页面
上。内容根据需求按需加载
组件,提升性能和开发效率。但是也带来了比较差的SEO
(无法根据具体内容提供个性化的SEO
)。
问题1 : Vue
又是如何做到 按需加载
更新页面的呢?
首先,要确定的就是 组件
与 访问路径
之间的对应关系。
问题2 : 组件
与 访问路径
的对应关系是如何确定的呢?
这就要来看看我们今天的主题 路由
了。
路由
- 介绍
路径
与 组件
的 映射
关系。根据这个 映射关系
,就可以知道访问的路径
应该 渲染 哪个组件
。
- 作用
修改
地址栏路径时,切换显示
匹配的组件
。
本文我们由浅入深,先从VueRouter
开始着手,了解路由,掌握VueRouter
的基本使用。
VueRouter
- 使用
- 下载
VueRouter
模板到项目中。例如:3.6.5版本
javascript
npm i vue-router@3.6.5
2、引入 + 注册 + 创建路由对象
javascript
// router/index.js文件
import Vue from 'vue'
import Router from 'vue-router' // 引入
Vue.use(Router) // 注册
const router = new Router()
3、注入,将路由对象注入到 new Vue
实例中,建立关联
javascript
import router from './router'
new Vue({
el: '#app',
router,
render: h => h(App)
})
4、创建需要的组件(views 目录
),配置路由规则
javascript
const router = new Router({
routes: [
{
path: '/publish-manage',
component: Layout,
redirect: '/publish-manage/wechat', // 路由重定向
meta: { title: '发布管理', icon: 'guide' },
alwaysShow: true,
children: [
{
path: 'wechat', // 地址栏的路径
name: 'wechat',
component: () => import('@/views/publish-manage/wechat-graphic/index'), // 异步引入组件
meta: { title: '微信图文管理' }
},
{
path: 'weibo',
name: 'weibo',
component: () => import('@/views/publish-manage/weibo/index'),
meta: { title: '微博发布' }
},
]
}
]
})
- 路由模块:将路由按模块拆分,利于维护。
绝对路径:
@
指代src
目录,可以用于快速引入组件。而不是一层一层./../../
的形式往上查找。
-
路由导航
- 声明式导航 ------ 导航链接
vue-router
提供一个全局组件router-link
,用于替换a标签
-
router-link
语法<router-link to='/路径值' />
必须传入
to
属性 来 指定路由路径值
-
router-link
高亮 自动给当前导航添加 两个类名。router-link-active
模糊匹配(一般用的多)router-link-exact-active
精准匹配 -
跳转传参
1、传参数:
to='/path?参数名=值'
2、接收参数:
$route.query.参数名
-
动态路由传参
1、配置动态路由
javascript{ path: '/search/:words?', // ? 表示参数可选 component: Search }
2、配置导航链接:
to='/path/参数值'
3、接收参数:
$route.params.参数名
-
路由
重定向 redirect
说明:
重定向 → 匹配path
后,强制跳转 path
路径 到 redirect
指向的路径
语法:
javascript
{
path: 匹配路径,
redirect: 重定向到的路径
}
- 路由 404
作用:当路径找不到匹配时,给个提示页面。
位置:配在路由最后
语法 :path: '*'
- 表示 任意路径,当前面的路由都没有匹配到时,命中这个。从而展示给用户
自定义的404页面
路由模式
通过 hash
和 history
两种方式实现前端路由,更新视图但不重新请求页面
是前端路由原理的核心之一。
-
路由的两种模式
hash
路由 :本质是利用URL
中的hash
,路径中携带#
原理: 监听路由变化(
onhashchange事件
),只有#
后面的地址发生变化,可以在windows
对象上监听这个事件:javascriptwindow.onhashchange = function (e) { let hash = location.hash; // 通过location对象获取hash地址,地址从#开始 } // onhashchange 事件在当前url的锚部门(以#开始)
因为
hash
发生变化的url
都会被浏览器记录下来,从而浏览器的前进后退都可以使用。hashchange
只能改变#
后面的url片段
history
路由
history api
给了前端完全的路由
,history api
可以分为两大部分:切换
和修改
注意: 在
history
模式下,可以自由的修改path
,但是history
模式最终的路由都体现在url
的pathName
中,这部分是会传到服务器
的,因此需要服务端
对每一个可能的path
值都作相应的映射
。当刷新时
,如果服务端
没有相应的响应或者资源,页面就会404
1、
切换历史状态
:包括back
、forward
、go
三个方法javascripthistory.go(-2); // 后退两次 history.go(2); // 前进两次 histor.back(); // 后退 history.forward(); // 前进
2、
修改历史状态
:包括pushState
、replaceState
两个方法, 这两个方法接受三个参数:stateObj
,title
,url
。- 两种路由模式的区别
1、前面的
hashchange
只能修改#
后面的Url 片段
,而history
,可以通过pushState
或者replaceState
设置与当前Url同源的任意Url
。2、
history
模式会将Url
修改的和正常请求后端的Url
一样,如果后端没有配置对应的路由
处理,则会返回404
错误,当用户刷新页面
时,浏览器会向服务器发送请求,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。
路由跳转
有两种语法:path路径
跳转 和 name命名路由
跳转
javascript
// 不带参数跳转
this.$router.push('路由路径')
this.$router.push({ path: '路由路径' })
this.$router.push({ name: '路由名' }) // 适合path路径较长的场景
// 例如:路由配置 -> { name: '路由名', path: '路由路径', component: 组件 }
// 带参数跳转
//`path路径`跳转 通过 `query传参`
this.$router.push('路由路径?参数1=参数值1&参数2=参数值2')
this.$router.push({
path: '/路由路径',
query: {
参数1: 参数值1,
参数2: 参数值2
}
})
//取参:
模板中 -> `$route.query.参数名`
script行为中 -> `this.$route.query.参数名`
//`动态路由`跳转传参
this.$router.push('/路由路径/参数值')
this.$router.push({ path: '/路由路径/参数值' })
// 取参:
模板中 -> `$route.params.参数名`
script行为中 -> `this.$route.params.参数名`
//`name命名路由` 跳转传参
this.$router.push({
path: '路由名',
query: {
参数1: 参数值1,
参数2: 参数值2
}
})
// 取参:
模板中 -> `$route.query.参数名`
script行为中 -> `this.$route.query.参数名`
this.$router.push({ // 只有 name命名路由 跳转有
path: '路由名',
params: {
参数1: 参数值1,
参数2: 参数值2
}
})
// 取参:
模板中 -> `$route.params.参数名`
script行为中 -> `this.$route.params.参数名`
this.$router.replace()
路由替换,与 this.$router.push
用法一致。
区别:
this.$router.push()
:跳转到指定url路径
,并向history栈中添加一个记录
,点击回退会返回到上一个页面。
this.$router.replace()
:跳转到指定url路径
,但是history栈中不会有记录
,点击返回会跳转到上上个页面(就是直接替换了的页面)
this.$router.go(n)
: 向前或向后跳转n个页面,n可为正整数或负整数。正整数 前进,负整数后退
组件缓存keep-alive
问题: 从列表到详情,又返回列表,数据重新加载 → 希望回到原来的位置,不重新加载数据
原因: 路由跳转后,列表组件销毁了,返回回来组件又重建了,所以数据重新加载了。
解决方案: 利用keep-alive
将组件缓存下来
1、keep-alive
是什么?
keep-alive
是 Vue
内置组件,当它 包裹 动态组件
时,会 缓存不活动的组件实例
,而不是销毁它们。
keep-alive
它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。
2、keep-alive
优点
在组件切换的过程中,把切换出去的组件保留在内存中,防止重新渲染DOM,可以减少加载时间喝及性能消耗,提高用户体验性。
3、keep-alive
原理
在 created
函数调用时将需要缓存的 VNode 节点
保存在 this.cache
中/在 render(页面渲染)
时,如果 VNode
的 name
符合缓存条件
(可以用 include
以及 exclude
控制),则会从 this.cache
中取出之前缓存的 VNode
进行渲染。
VNode
:虚拟DOM
,其实就是一个JS对象
4、keep-alive
使用
参数名 | 值 | 描述 |
---|---|---|
include | 字符串或正则表达式 | 只有名称匹配的组件才会被缓存 |
exclude | 字符串或正则表达式 | 任何名称匹配的组件都不会被缓存 |
max | 数字 | 最多可以缓存多少组件实例 |
include
/exclude
值 是组件中的 name 命名,而不是 路由名
javascript
// 缓存 组件名 为 test 的组件
<keep-alive include='test'>
<router-view />
</keep-alive>
// 缓存 组件名 为 a 或 b 的组件
<keep-alive include='a, b'>
<router-view />
</keep-alive>
// 使用正则表达式, 需要用v-bind
<keep-alive :include='/a|b/'>
<router-view />
</keep-alive>
// 动态判断
<keep-alive :include='/a|b/'>
<router-view />
</keep-alive>
// 与 transition 一起使用
<transition>
<keep-alive :include='/a|b/'>
<router-view />
</keep-alive>
</transition>
// 使用数组, 需要用v-bind
<keep-alive :include='["a", "b"]'>
<router-view />
</keep-alive>
5、keep-alive
触发的生命周期
activated
当组件被激活(使用)
的时候触发 → 进入这个页面的时候触发deactivated
当组件不被使用
的时候触发 → 离开这个页面的时候触发
组件缓存后,就不会执行
created
、mounted
、destroyed
等钩子函数
不同情况钩子函数执行情况:
javascript
不同情况钩子函数执行情况:
// 不使用 keep-alive
`beforeRouteEnter` → `created` → `mounted` → `destroyed`
// 使用 keep-alive
`beforeRouteEnter` → `created` → `mounted` → `activated` → `deactivated`
// 再次进入缓存的页面,
只会触发
`beforeRouteEnter` → `activated` → `deactivated` 。`created` 和`mounted`不会再执行。