文章目录
一、认识vue-router
目前前端流行的三大框架,都有自己的路由实现:
- Angular的ngRouter
- React的ReactRouter
- Vue的vue-router
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
vue-router是基于路由和组件的
- 路由用户设定访问路径的,将路径和组件映射起来。
- 在vue-router的单页面应用中,页面的路径的改变就是组件的切换。
二、安装和使用vue-router
第一步:安装vue-router
npm i vue-router@3 -S
第二步:在模块化工程中使用它(因为是一个插件,所以可以通过Vue.use()来安装路由功能)
- 导入路由对象,并且调用Vue.use(VueRouter)
- 创建路由实例,并且传入路由映射配置
- 在Vue实例中挂载创建的路由实例
使用vue-router的步骤:
- 第一步:创建路由组件
- 第二步:配置路由映射:组件和路径映射关系
- 第三步:使用路由:通过和
代码实现步骤:
(1) 创建router实例
// src/plugins/router.js
// 1-导入 Vue 和 vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
// 2-安装插件包到Vue上
Vue.use(VueRouter)
// 3-配置路由和组件之间的映射关系
const routes = [
... ...
];
// 4-创建VueRouter实例对象
const router = new VueRouter({
// 3-配置路由和组件之间的应用关系
routes
});
// 5-导出router对象传入到vue实例
export default router
(2) 挂载到Vue实例中
// main.js
import Vue from 'vue'
import APP from './APP.vue'
// 1-引入注册router.js文件
import router from './router/router.js'
Vue.config.productionTip = false;
new Vue({
render: h => h(APP),
// 2-挂载到Vue实例中
router,
}).$mount('#app')
- 第一步:创建路由组件
- 第二步:配置组件和路由的映射关系
// 3-配置路由和组件之间的映射关系
const routes = [
{
name: '名字'
path: './home',
component: home
},
{
name: '名字'
path: './home',
component: {
default: mainComponent, // 命名视图
sidebar: sidebarComponent,
},
alias: './homes' // 别名
},
{
path: '/',
redirect: '/home'
},
]
- 第三步:使用路由
<router-link to="/home"></router-link>
<router-view>展示区</router-view>
//命名视图
<router-view class="view sidebar" name="sidebar"></router-view>
//<router-link>:该标签是一个vue-router中已经内置的组件,默认情况下被渲染成一个<a>标签。
//<router-view>:该标签会根据当前的路径,动态渲染出不同的组件。
三、路由的默认路径
默认情况下,进入网站的首页,我们希望渲染首页的内容。但是我们的实现中,默认没有显示首页组件,必须让用户点击才可以。
如何可以让路径默认跳转到首页,并且渲染首页组件呢?
我们需要多配置一个映射就可以了
// 方式一:字符串路径path
{
path: '/a', // 默认页
redirect: '/b' // 配置型跳转
}
// 方式二:name
{ path: '/a', redirect: {name: 'b'} }
// 方式三:动态返回重定向目标
{ path: '/a', redirect: to => {
/* 方法接收 目标路由 作为参数;return 重定向的 字符串路径/路径对象 */
}}
配置解析:
我们在routes中又配置一个映射
- path配置的是根路径:/
- redirect是重定向,也就是我们将根路径重定向到/home的路径下,这样就可以得到我们想要的结果了。
404
{
path: '*',
component: NoPage组件
}
四、路由的History模式hash模式
改变路径的方式有两种:(都不重新刷新页面)
- URL 的 hash
- HTML5 的 history
hash | history | |
---|---|---|
url显示 | 有#,很Low | 无#,好看 |
回车刷新 | 可以加载到hash值对应页面 | 一般就是404掉了 |
支持版本 | 支持低版本浏览器和IE浏览器 | HTML5新推出的API |
默认情况下,路径改变使用URL的 hash,如果希望使用HTML5的history模式,进行如下的配置:
// 4-创建VueRouter实例对象
const router = new VueRouter({
// 3-配置路由和组件之间的应用关系
routes,
// mode:'hash'//哈希模式 location.href
mode: 'history' //历史记录 history.pushState
});
Hash 模式:#—hash符号,中文名哈希符或锚点。路由的哈希模式是利用window的监听onhashchange事件,当url中的哈希值(#后面的值)发生变化时,前端可以监听并做出响应。
History 模式:History API 提供了 pushState() 和 replaceState() 方法来增加或替换历史记录。可以将url替换并且不刷新页面。但需要后台配置,否则输入的除首页外都为404(当然系统内跳转可以)。问题:不怕前进,不怕后退,就怕刷新。
- pushState方法不会触发页面刷新,只是导致history对象发生变化,地址栏会有反应。
history 对象通常具有以下属性和方法:
- length: number 浏览历史堆栈中的条目数
- action: string 路由跳转到当前页面执行的动作,分为 PUSH, REPLACE, POP
- location: object 当前访问地址信息组成的对象,具有如下属性:
- pathname: string URL路径
- search: string URL中的查询字符串
- hash: string URL的 hash 片段
- state: string 例如执行 push(path, state) 操作时,location 的 state 将被提供到堆栈信息里,state 只有在 browser 和 memory history 有效。
- push(path, [state]) 在历史堆栈信息里加入一个新条目。
- replace(path, [state]) 在历史堆栈信息里替换掉当前的条目
- go(n) 将 history 堆栈中的指针向前移动 n。
- goBack() 等同于 go(-1)
- goForward 等同于 go(1)
- block(prompt) 阻止跳转
- history 对象是可变的,因为建议从 的 prop 里来获取 location,而不是从 - - history.location 直接获取。
五、router-link属性介绍(申明式跳转)
- to:用于指定跳转的路径
- tag:tag可以指定之后渲染成什么组件,比如我们下面的代码会被渲染成一个
- 元素,而不是 。 如:
<router-link to='/home' tag='li'>
- replace:replace不会留下history记录,所以指定replace的情况下,后退键返回不能返回到上一个页面中
- active-class:当对应的路由匹配成功时,会自动给当前元素设置一个router-link-active的class,设置active-class可以修改默认的名称。
<router-link to="/home"></router-link>
<router-link to="/home" tag='li'></router-link>
<router-link to="/home" tag='li' active-class='css类名'></router-link>
六、路由编程式跳转
有的时候,页面的跳转可能需要执行相应的JavaScript代码,这个时候,就可以使用第二种跳转方式了。
比如我们将代码修改如下:
this.$router.push(string|obj)
this.$router.push({name:'...'})
//添加一个路由 (记录到历史记录)
this.$router.replace({name:'...'})
//替换一个路由 (不记录到历史记录)
this.$router.go(-1|1)|back()
//回退/前进
七、动态路由
在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:
/user/aaa或/user/bbb
路由传参
除了有前面的/user之外,后面还跟上了用户的ID,这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)
八、路由懒加载
路由懒加载的方式
- 方式一:结合Vue的异步组件和Webpack的代码分析
const Home = resolve => {
require. ensure(['../ components/Home.vue'],
() => {resolve(require('../ components/Home.vue'))
})
};
- 方式二:AMD写法
const About = resolve => require(
[' ../ components/ About.vue'], resolve
);
- 方式三:在ES6中,我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割
const Home = () => import(' . ./ components/Home.vue ' )
路由懒加载的效果
九、嵌套路由实现
// src/plugins/router.js
routes=[
{},
{path:'xx/:变量',component:xx}, //在当前层级展示区展示
{
path:xx
component:xx
children:[ //子路由
{path:':变量', ..} //在子展示区展示
{.. ,redirect: 'xx'} //默认页
]
},
{}
]
十、传递参数的方式
传递参数主要有两种类型:params和query
1. params的类型
- 配置路由格式:/router/:id
- 传递的方式:在path后面跟上对应的值
- 传递后形成的路径:/router/123,/router/abc
2. query的类型
- 配置路由格式:/router,也就是普通配置
- 传递的方式:对象中使用query的key作为传递方式
- 传递后形成的路径:/router?id= 123,/router?id=abc
模式 | 匹配路径 | 获取参数 |
---|---|---|
/user/:username | /user/zhansan | $route.params.username |
/user?:username | /user?username=zhansan | $route.query.username |
// 组件中
<router-link to='xx/参数?a=1&b=2'></router-link>
<router-link
:to='{
name: "名字", // 命名路由
params:{id:1},
query:{a:2,b:3}
}'
></router-link>
// 组件接参
//template
{{$route.params/query/path}}
//script
this.$route.params/query
当使用路由参数时,例如从 /user/ligang 导航到 user/lg,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
方式一:简单地watch(监测变化)$route对象
watch: {
'$route' (to, from) {
// 对路由变化作出响应...
}
}
方式二:使用 2.2 中引入的 beforeRouteUpdate 守卫
beforeRouteUpdate (to, from, next) {
// 对路由变化作出响应...不要忘记调用next()
}
十一、导航守卫的使用
我们可以利用beforeEach来完成标题的修改
首先,我们可以在钩子当中定义一些标题,可以利用mate来定义;其次,利用导航守卫修改我们的标题。
导航钩子的三个参数解析:
- to:即将要进入的目标的路由对象
- from:当前导航即要离开的路由对象
- next:调用该方法后,才能进入下一个钩子
// src/plugins/router.js
//前置
router.beforeEach((to, from, next) => {
// to: 目标路由 $route
// from: 当前路由 $route
// next() 跳转 一定要调用
next(false);//走不了
next(true);//走你
next('/login')//走哪
next({path:'/detail/2',params:{},query:{}})//带点货
// 守卫业务
if(to.path=='/login' || to.path=='/reg' || to.path=='/register'){
//判断是不是登录了
//axios请求 携带 token
next()
}else{
next('/login');
}
})
//后置
router.afterEach((to,from)=>{
//全局后置守卫业务
})
如果是后置钩子,也就是afterEach,不需要主动调用next()函数。上面我们使用的导航守卫,被称之为全局守卫。
路由独享守卫
// src/plugins/router.js -> routes
{
path: '/user',
component: User,
beforeEnter: (to,from,next)=>{ //路由独享守卫 前置
console.log('路由独享守卫');
if(Math.random()<.5){
next()
}else{
next('/login')
}
}
},
独享,没有后置
组件内部守卫
//组件内部钩子
beforeRouteEnter (to, from, next) {//前置 运行在beforeCreate 之前
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {//后置 运行在beforeDestory之前
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
路由元信息
//src/plugins/router.js
{
path: '/home',
component: Home,
meta: { requiresAuth: true }
}
访问 meta 字段
this.$route.meta
to.meta from.meta
滚动行为
SPA是单页面,只有一个滚动条,路由跳转时滚动条会影响到元素位置,使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样
对于所有路由导航,简单地让页面滚动到顶部
// src/plugins/router.js
const router = new VueRouter({
scrollBehavior (to, from, savedPosition) {
//计算位置
return { x: 0, y: 0 }
}
})
Vue-router 相关问题:
Vue-router 中hash模式和history模式的区别?
解答:hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。那么什么时候要用history模式呢?如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传。当然其功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦。