文章目录
前言
什么是路由及其映射关系?
路由(routing)是网络工程里的一个术语。在生活中,我们都听过路由器,其中路由器提供了两种机制:路由和转送。路由是决定数据包从来源到目的地的路径,转送将输入端的数据转移到合适的输出端。在路由中有一个非常重要的概念叫路由表。路由表本质就是一个映射表,决定了数据包的指向。
一、vue-router实现的两种模式(vue-router面试题重点之一)
前端路由vue-router实现有两种模式:hash模式
和history模式
。如果需要改变url,但是页面不进行整体的刷新的话,我们可以通过url的hash和HTML5的history方法来处理。
1、hash模式
url的hash是用createWebHashHistory()
创建的,(vue-router的默认模式)也就是锚点(#),本质上是改变window.location的href属性。我们可以通过直接赋值location.hash来改变href,但是页面不发生刷新。
2、history模式
HTML5的history模式是用createWebHistory()
创建的。
HTML5的history模式:它有五种模式改变url而不刷新页面。
pushState(对象参数data,title参数,url)函数类似于栈结构的进栈,back函数相当于出栈,
replaceState(对象参数data,title参数,url)函数:代替上一个url;
go函数以及foeward函数。
history.back()等价于history.go(-1);history.forward()等价于history.go(1);这三个接口等同于浏览器的前进后退。
二、安装和使用
2.1 安装
vue-router官方文档地址:Vue Router 。详情可见官方文档,说的非常详细,拓展深度也很不错。
vue-router相关函数及方法可见:API参考
官方给出了三种安装方式:CDN/直接下载、npm安装以及从GitHub克隆构建。个人推荐npm下载,通过以下指令安装。其中@是指定某个具体版本来安装(根据你需要安装的版本号来更改)。
npm install vue-router@4
题外话:如果安装速度比较慢的话可以使用淘宝NPM镜像,即cnpm(gzip压缩支持)命令行工具代替默认的npm:
npm install -g cnpm --registry=https://registry.npm.taobao.org
这样就可以使用cnpm命令来安装模块了:
cnpm install [name]
2.2 配置及使用
2.2.1 牛刀小试
提前声明:在创建项目使用vue-router时,使用的是老版本的vue-cli2(创建项目命令:vue init webpack [项目名称]
)。我们安装vue-router后在模块化工程中使用它,它是一个插件,可以通过Vue.user来安装路由功能。
生成的文件夹结构如下图(有些许更改):
第一步:导入路由对象,并且通过Vue.use
调用;
第二步:创建路由实例,并且传入路由映射配置;
第三步:在Vue实例中挂载创建的路由实例。
使用vue-router的步骤:
①创建路由组件。
创建一个home组件和about组件:Home.vue/About.vue
<template>
<div>
<h2>我是首页</h2> // <h2>我是关于</h2>
<p>我是首页内容</p> // <p>我是关于内容</p>
</div>
</template>
<script>
export default {
name: "Home" //name: "About"
}
</script>
<style scoped>
</style>
②配置路由映射,即组件和路径映射关系:index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../components/Home.vue'
import About from '../components/About.vue'
Vue.use(Router)
export default new Router({
// 配置路由和组件的应用关系
routes: [
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
})
③通过<router-link>和<router-view>使用路由:App.vue
<template>
<div id="app">
// router-link的to属性相当于a标签的href属性,用于指定跳转的路径。
<router-link to="/Home">首页</router-link>
<router-link to="/About">关于</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
vue-router初试成功!
<router-link>
标签:
其中<router-link> 是一个vue-rouer中已经内置的组件,它会被渲染成一个<a>标签。
1、它除了上面的to属性,还有一个tag属性,用来指定<router-link>之后渲染成什么组件,比如:
// 会把首页渲染成一个按钮,但是该属性在vue-cli3及之后版本被废除了
<router-link to = "/home" tag = "button">首页</router-link>
2、replace属性:在我们之前来回点击切换首页和关于两个按钮时,此时浏览器内部使用的是pushState方法,此时浏览器内留有记录,可以进行后退操作。但是replace不会留下history记录,所以指定replace的情况下,后退键返回不能返回到上一个页面中。
<router-link to = "/home" tag = "button" replace>首页</router-link>
3、active-class属性:当<router-link>对应的路由匹配成功时,会自动给当前元素设置一个router-link-active的class(即点击哪个按钮就给它加上在一个类名,这个使用场景可以是这样:比如点击哪个按钮,哪个按钮的字体颜色就改变,只需给这个类名添加一个样式即可),设置active-class可以修改默认的class名称(如 active-class = “×××”)。在进行高亮显示的导航菜单或者底部tabbar时,会使用到该类。但是通常不会修改类的属性,会直接使用默认的router-link-active即可。
<router-view>
标签:
<router-view >会根据当前的路径,动态渲染出不同的组件。
网页的其他内容,比如顶部的标题/导航,或者底部的一些版权信息等会和<router-view>处于同一个等级。在路由切换时,切换的是<router-view>挂载的组件,其他内容则不会发生改变。
我们知道,当我们进入一个网站时,这个网站会自动刷新出它的首页内容。但是在我们的实现中,默认没有显示首页组件,必须让用户点击首页才可以显示。如何可以让路径默认跳到到首页,并且<router-view>渲染首页组件呢?非常简单,我们只需要多配置一个映射就可以了。即在routes中又配置了一个映射。path配置的是根路径: /,redirect就是重定向,也就是我们将根路径重定向到/home的路径下,这样就可以得到我们想要的结果了。
{
path: '/',
redirect: '/home'
},
2.2.2 美观Vue路由
但是此时我们的路径表示都是hash模式,现在我们希望将它变成HTML5的history模式,也就是想去掉vue路由url中的#号。我们可以直接在配置路由和组件关系的index.js中添加如下语句即可。
mode: 'history',
hash模式下在内部传递的实际 URL 之前使用了一个哈希字符(#
)。由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。原来路由中有个#
号并不美观:
2.2.3 其它实现及$router
思考:如果用上我们以前学过的vue-core知识来代替<router-link>的话,我们该怎么实现上述效果呢?我们可以先进行如下简单的构建并给组件添加相关methods方法。
// 相当于实现<router-link>标签的tag属性
<button @click="homeClick">首页</button>
<button @click="aboutClick">关于</button>
<router-view></router-view>
但是随之我们可以发现,虽然我们可以在页面上通过这两个按钮来回跳转,但是路由并不会随之跳转,即url不随之改变。所以,我们可以想到这么一个方法:在methods中给按钮点击行为添加相关代码实现路由跳转。通过如下语句:
homeClick(){
// 不要绕过vue-router直接使用history的方法来改变
// 也可以使用replace方法,只不过进行不了浏览器的前进后退操作
this.$router.push('/home'); // 相当于实现<router-link>标签的to属性
},
// aboutClick(){ 类同 }
这样我们就仍然实现了路由的跳转了。
其中 $router 属性来源于vue-router的源码,在其中所有的组件中都有该属性,所以我们通过 this.$router 可以使用该属性及其相关方法。
三、动态路由的使用
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果。
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: User }
]
})
现在呢,像 /user/foo 和 /user/bar 都将映射到相同的路由。
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内使用。于是,我们可以通过使用{{$route.params.id}}
来输出当前用户的 ID。
另外,一个路由中可以设置多段“路径参数”,对应的值都会设置到 $route.params
中:
模式 | 匹配路径 | $route.params |
---|---|---|
/user/:username | /user/evan | { username: 'evan' } |
/user/:username/post/:post_id | /user/evan/post/123 | { username: 'evan', post_id: '123' } |
四、路由懒加载的使用
我们知道路由中通常会定义很多不同的页面,一般情况下这个页面最后被打包在一个js文件中。但是,页面这么多且全部放在一个js文件中,必然会造成这个页面非常的大。如果我们一次性从服务器请求下来这个页面,可能需要花费一定的时间,甚至用户的电脑上还出现了短暂空白的情况。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。也就是使用路由懒加载就可以了。路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块,只有在这个路由被访问到的时候,才加载对应的组件。
懒加载的方式
在index.js文件中将import Home from '../components/Home.vue'
更改成其他以下写法:
方式一:结合 Vue 的异步组件和 Webpack 的代码分析
const Home = resolve => { require.ensure(['../components/Home.vue'],
() => { resolve(require('../components/Home.vue')) })};
方式二:AMD写法
const Home = resolve => require(['../components/Home.vue'],resolve);
方式三:在ES6中,有更简单的写法来组织Vue 的异步组件和 Webpack 的代码分割(推荐)
const Home = () => import('../components/Home.vue');
经过懒加载后打包项目,我们可以发现多了三个js文件(因为代码里只实现了三个组件的懒加载)。这样使打包出来的js文件更小,用户在请求时的效率也就更高了。(题外话:打包的js文件中app.js是用来存放我们在当前应用程序开发的所有业务代码,vendor.js指的是第三方协助我们开发的一些工具或框架比如vue和vue-router等,manifest.js是为我们打包的代码做底层支撑。)
五、嵌套路由
一些应用程序的 UI 由多层嵌套的组件组成。如百度的首页,此时它的url是https://www.baidu.com,当我们点击它首页组件上的"更多“组件时,它的url变成了https://www.baidu.com/more/。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构。当我们通过点击跳转到其它页面时,url也随之更改。通过 Vue Router,我们可以使用嵌套路由配置来表达这种关系。
首先,我们新建一个Us.vue文件随便写点<h2>message1</h2>
并导出,因为我们是想把它放在在“关于”这个界面下的,所以我们在About.vue文件加上下列语句使它能够渲染在“关于”的界面上
<router-link to="/about/us">我们</router-link>
<router-view></router-view>
要将Us组件渲染到这个嵌套的router-view 中,我们需要在路由中配置 children:
{
path: '/about',
component: About,
children: [
{
// 当 /about/us 匹配成功时,User将被渲染到About的 <router-view> 内部
path: 'us',
component: Us
}
]
},
children(子路由)
配置只是另一个路由数组,就像 routes 本身一样。因此,我们可以根据自己的需要,不断地嵌套视图。效果如下图:
注意,以 /
开头的嵌套路径将被视为根路径。这允许我们利用组件嵌套,而不必使用嵌套的 URL。
六、Vue Router传递参数
1、query方式传参和接收
//传参
this.$router.push({ path:'/xxx', query:{ name:name, age:age, height:height } })
接收参数:
this.$route.query.name // query.age/query.height
2、params方式传参和接收
//传参
this.$router.push({ path:'xxx', params:{ name:name, age:age, height:height } })
接收参数:
this.$route.params.name // params.age/params.height
注意混淆:传参是this.$router
,接收参数是this.$route
。