文章目录
一:认识路由及路由规则
随着Ajax的出现, 有了前后端分离的开发模式。
后端只提供API来返回数据, 前端通过Ajax获取数据, 并且可以通过JavaScript将数据渲染到页面中,
这样做最大的优点就是前后端责任的清晰, 后端专注于数据上, 前端专注于交互和可视化上。
随后在后端路由的基础上诞生了前端路由。
有必要提前了解url的hash和html5的history
vue-router前端路由的一种,是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。其官方网站: https://router.vuejs.org/zh/
vue-router是基于路由和组件的
- 路由用于设定访问路径, 将路径和组件映射起来.
- 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换
二:安装配置vue-router
vue-router常见安装方式有cdn、npm、vue cli(优先学习npm方式 熟悉webpack)
-
安装:
例:npm install vue-router --save或者新版vue cli中vue ui可视化插件方式安装
安装完成会在配置文件依赖描述中出现
(填写依赖再npm也可行)
-
配置:
在模块化工程中运用 项目结构:
-
导入路由对象 并且调用Vue.use(Vue-router)
-
创建路由实例 并且传入路由映射配置
-
在vue示例中挂载创建的路由实例
//router/index.js import Vue from 'vue' //配置路由相关的信息 import VueRouter from 'vue-router' //通过Vue.use(插件),安装插件 Vue.use(VueRouter) //配置映射关系 const routes = [] //创建VueRouter对象 const router = new VueRouter({ //es6增强写法 routes }) //导出后在main.js导入并挂载 export default router
//main.js //导入router 自动搜寻/index.js import router from './router' new Vue({ router, //挂载添加路由 render: h => h(App) }).$mount('#app')
-
三:使用vue-router
- 创建路由组件
- 配置路由映射:组件和路径映射关系
- 使用理由:通过
<router-link>
和<router-view>
//router/index.js
//配置映射关系
const routes = [
//例:
{
path: '/test',
name: 'test',
component: testView
},
]
//components/test.vue
//组件内容
<template >
<div class="a">
我是test组件
</div>
</template>
<script>
//到处test组件
export default {
name: "test",
};
</script>
<style scoped>
.a {
width: 100px;
height: 100px;
background-color: red;
}
</style>
//app.vue 组件内容挂上
<template>
<div id="app">
<router-link to="test"></router-link>
<router-view></router-view>
</div>
</template>
启动服务后可以使用路由访问:
四:路由的默认值和修改为history模式
路由默认值
如何可以让路径默认跳到到首页, 并且<router-view>
渲染首页组件呢?
只需要配置多配置一个映射就可以了 如下图:
//index.js
//配置映射关系
const routes = [
{
path:'/',
redirect:'/default'
//如果默认路径是/则重定向到/default
},
]
示例:
//views/default.vue
<template>
<div>
<h2>
default默认首页面是我
</h2>
</div>
</template>
<script>
export default {
name: 'defaultView',
components: {
}
}
</script>
<style>
h2{
color: pink;
font-size: 100px;
}
</style>
//router/index.js
import Vue from 'vue'
//配置路由相关的信息
import VueRouter from 'vue-router'
import testView from '../views/testView.vue'
import defaultView from '../views/default.vue'
//通过Vue.use(插件),安装插件
Vue.use(VueRouter)
//配置映射关系
const routes = [
{
path:'/',
redirect:'/default'
//如果默认路径是/则重定向到/default
},
{
path:'/test',
name:'test',
component:testView
},
{
path:'/default',
name:'default',
component:defaultView
}
]
//创建VueRouter对象
const router = new VueRouter({
//es6增强写法
routes
})
//导出后在main.js导入并挂载
export default router
//App.vue
<template>
<div id="app">
<div>
<router-link to="test">testView</router-link>
<router-link to="default">default默认首页</router-link>
<router-view></router-view>
</div>
</div>
</template>
效果图:
history模式
改变路径的方式有两种:
-
URL的hash
-
HTML5的history
默认情况下, 路径的改变使用的URL的hash.
使用HTML5的history模式, 非常简单, 进行如下配置即可:
const router = new VueRouter({
//es6增强写法
routes,
mode:'history'
})
示例效果图:
可见hash的#已经不见了
五:router-link补充
其他属性:
- tag: tag可以指定
<router-link>
之后渲染成什么组件, 比如上面的代码会被渲染成一个<li>
元素, 而不是<a>
- replace: replace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中
- active-class: 当
<router-link>
对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称.
在进行高亮显示的导航菜单或者底部tabbar时, 会使用到该类.
但是通常不会修改类的属性, 会直接使用默认的router-link-active即可.
示例:
<template>
<div id="app">
<div>
<router-link to="test" tag="button" replace >testView</router-link>
<router-link to="default" tag="li">default默认首页</router-link>
<router-link to="test" tag="button" replace active-class="active">testView222</router-link>
<router-view></router-view>
</div>
</div>
</template>
<style>
.active{
background-color:red;
}
.router-link-active{
color: blue;
}
</style>
效果图:
修改linkActiveClass
效果也同样可以显示出来
六、路由代码跳转
有时候, 页面的跳转可能需要执行对应的JavaScript代码, 这个时候, 就可以使用第二种跳转方式了
比如, 我们将代码修改如下:
效果图:
七、动态路由
在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:
- /user/aaaa或/user/bbbb
- 除了有前面的/user之外,后面还跟上了用户的ID
- 这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)。
效果图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SZGTaTRG-1622731235653)(https://gitee.com/wx_7585a01835/web_markdowm_img/raw/master/img/士大夫地方 (1)].gif)
八、路由懒加载
方式一: 结合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')
九、嵌套路由
嵌套路由是一个很常见的功能
实现嵌套路由有两个步骤:
-
创建对应的子组件, 并且在路由映射中配置对应的子路由.
-
在组件内部使用
<router-view>
标签.
效果图:
十、参数传递
传递参数的方式
准备工作:
为了演示传递参数, 我们这里再创建一个组件, 并且将其配置好
- 第一步: 创建新的组件Profile.vue
- 第二步: 配置路由映射
- 第三步: 添加跳转的
<router-link>
传递参数主要有两种类型: params和query
- params的类型:
- 配置路由格式: /router/:id
- 传递的方式: 在path后面跟上对应的值
- 传递后形成的路径: /router/123, /router/abc
- query的类型:
- 配置路由格式: /router, 也就是普通配置
- 传递的方式: 对象中使用query的key作为传递方式
- 传递后形成的路径: /router?id=123, /router?id=abc
传递参数方式一: router-link
//porfile.vue
<template>
<div>
<h2>profile页面是我</h2>
<h3>userId:{{ $route.params.userId }}</h3>
<h3>age:{{ $route.query.age }}</h3>
<h3>size:{{ $route.query.size }}</h3>
</div>
</template>
<script>
export default {
name: "profile",
components:{
}
};
</script>
<style scoped>
h2{
color: rgb(90, 184, 140);
font-size: 100px;
}
</style>
//router/index.js添加
const profile = () => import('../views/profile.vue')
{
path:'/profile/:userId',
component:profile
}
//App.vue
<template>
<div id="app">
<div>
<router-link to="/default">default</router-link>
<div></div>
<router-link to="/Home">Home</router-link>
<div></div>
<router-link :to="/profile/+userId">profile(params)</router-link>
<div></div>
<router-link :to="{
path:'/profile/'+userID,
query:{age:20,size:18}
}">porfile(query)</router-link>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
userId:234
}
},
}
</script>
<style>
</style>
效果图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h0s2XWeB-1622731235662)(https://gitee.com/wx_7585a01835/web_markdowm_img/raw/master/img/路由参数传递 (1)].gif)
传递参数方式二: JavaScript代码
//App.vue
<template>
<div id="app">
<div>
<button>default</button>
<button @click="toHome">Home</button>
<button @click="toprofile">profile</button>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
userId:234
}
},
methods: {
toHome(){
this.$router.push('/Home/'+this.userId)
},
toprofile(){
this.$router.push({
path:'/profile/'+this.userId,
query:{age:20,size:18}
})
}
},
}
</script>
<style>
</style>
获取参数
获取参数通过$route对象获取的.
在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route ,并且当路由切换时,路由对象会被更新。
r o u t e 和 route和 route和router是有区别的
- r o u t e r 为 V u e R o u t e r 实 例 , 想 要 导 航 到 不 同 U R L , 则 使 用 router为VueRouter实例,想要导航到不同URL,则使用 router为VueRouter实例,想要导航到不同URL,则使用router.push方法
- $route为当前router跳转对象里面可以获取name、path、query、params等
十一、导航守卫
导航守卫主要用来通过跳转或取消的方式守卫导航。
有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
(记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察$route对象来应对这些变化,或使用beforeRouteUpdate的组件内守卫)
- vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.
- vue-router提供了
beforeEach
和afterEach
的钩子函数, 它们会在路由即将改变前和改变后触发.
beforeEach函数:
示例:
前置守卫(guard)beforeEach
为例来完成标题的修改(后置钩子(hook)afterEach
暂时了解)
- 在钩子当中定义一些标题, 可以利用meta(元数据)来定义
- 其次, 利用导航守卫,修改我们的标题
- 导航钩子的三个参数解析:
to
: 即将要进入的目标的路由对象.from
: 当前导航即将要离开的路由对象.next
: 调用该方法后, 才能进入下一个钩子.
//router/index.js
{
path:'/default',
name:'default',
component:defaultView,
meta:{
title:'default'
}
}, {
path:'/profile/:userId',
component:profile,
meta:{
title:'profile'
}
}
router.beforeEach((to,from,next) => {
//从from跳转到to
document.title = to.matched[0].meta.title
console.log(to);
next()
} )
效果图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8wicIu3k-1622731235665)(https://gitee.com/wx_7585a01835/web_markdowm_img/raw/master/img/导航守卫 (1)].gif)
附加问题:
beforeEach中变量from定义了未引用 ealint代码校验报错解决:
// package.json
rules: {
"no-unused-vars":"off"
}
补充:
- 如果是后置钩子, 也就是afterEach, 不需要主动调用next()函数.
- 补充二: 上面我们使用的导航守卫, 被称之为全局守卫.
- 路由独享的守卫
- 组件内的守卫
具体参考Vue Router官网更新数据
十二、keep-alive
- keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
- 它们有两个非常重要的属性:
- include - 字符串或正则表达,只有匹配的组件会被缓存
- exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
- router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存:
- 通过create声明周期函数来验证
//App.vue
<keep-alive>
<router-view>
<!-- 所有匹配到的视图子组件都会被缓存 -->
</router-view>
</keep-alive>