本文主要介绍如何使用路由控制来实现将一个单页面网站扩展成多页面网站,包括页面扩展的逻辑,vue的官方路由vue-router的基本用法以及扩展用法
本系列前文传送门
一、场景说明
我们在进行网站开发的时候,大多数都是需要有多个页面展示不同内容或者提供不同功能。每个页面单独启动一个项目的做法不太现实,实际业务中是一个项目中,一个页面对应项目代码中一个代码文件,然后通过浏览器地址的不同后缀(比如/home
, /about
, /prodcut
, /center
等等)来对应到不同的代码文件,进而在浏览器上展示不同的内容和提供不同的功能。
二、基本的页面扩展
页面扩展是在扩什么
在前文介绍如何快速开始一个项目时,我们已经探索到了页面渲染的逻辑,即:
- 浏览器根据地址栏输入的地址,会得到一个
path
- 我们在代码里指明某个
path
对应某个component
- 我们在
component
编写我们要展示的内容和功能
就完成了从代码到浏览器内容的关联和渲染展示。
当我们要跳转到一个新的页面的时候,一般地址栏的地址会跟随着变化,会有一个新的地址,即会有一个新的path
。
所以,当我们要增加一个新的页面的时候,其实就是新增一个从代码到浏览器地址的关联关系。即,在src/router/index.js
中
将
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
改成
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/about',
name: 'About',
component: HelloWorld
}
]
})
这里我们在routes
的值中增加了一个元素,即增加了一个从浏览器地址后缀/about
关联到代码HelloWorld
的关联关系,只不过我们这里关联的代码没有额外写,而是直接再次用了HelloWorld
页面的代码。
现在我们的项目就有两个页面了,可以分别通过浏览器地址栏输入http://localhost:8080/#/
和http://localhost:8080/#/about
来访问两个页面。
由于我们使用了同样的代码来展示两个页面,所以看到的页面内容其实是一样的。打个比方说,如果我们的项目现在是一本两页的书,那么这两页的内容是一样的。
可以确定的是,我们现在确实是两个页面,而不是一个页面。如果需要验证这一点,可以把我们刚才的代码改动先注释掉或者删掉,然后直接访问http://localhost:8080/#/about
,可以看到页面的内容其实跟HelloWorld
页面内容不一样,而是下面的仅有一个logo图片的页面:
创建新页面的代码,让页面内容变化起来
现在我们需要编写一个新的代码来对应路径/about
,使得浏览器展示我们想展示的内容。因为我们的代码是由框架生成的标准化代码,所以这件事变得很简单,我们可以这样操作:
- 直接复制一份
HelloWorld.vue
代码副本 - 然后将副本命名为
About.vue
- 在
src/router/index.js
中导入About
- 再将路径
/about
对应的代码从HelloWorld
改成About
这样我们就完成了两个路径对应两个页面,两个页面用的是不同代码。然后我们修改About.vue
里面的内容,让我们可以直观地从浏览器展示的内容观察到这一点。
进入App.vue
,然后修改底下msg变量的值
将
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Hello Vue World!'
}
}
}
改成
export default {
name: 'HelloWorld',
data () {
return {
msg: 'About Vue World!'
}
}
}
保存后,重新打开浏览器可以看到我们/about
对应的页面内容已经发生变化:
至此,我们就完成了网站页面从单页面网站升级成多页面网站的过程~ (●ˇ∀ˇ●)
对地址栏的地址格式进行一个优化
我们可以看到我们的两个页面的地址栏输入是http://localhost:8080/#/
和http://localhost:8080/#/about
,所以我们目前的地址栏格式是http://localhost:8080/#/XXXXX
。
这种格式其实我们在日常浏览其他网站的时候并不常见,更常见的格式是http://localhost:8080/about
,也就是我们可以优化一下地址格式,尝试将#/
从地址中移除。
要实现这一点我们只需要在src/router/index.js
中,在创建router实例的时候,指定一个mode
参数,如下:
export default new Router({
mode: "history",
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/about',
name: 'About',
component: About
}
]
})
重新打开浏览器,就可以看到地址格式已经是我们希望的样子了:
三、避免页面频繁重新加载的路由用法
到这里,我们可以做一个回顾,我们在给一个网站"安装路由器"的时候都做了哪些事情?
- 首先我们使用了
vue
的官方路由包vue-router
,这个包在一开始初始化项目时通过命令行提示选择了Yes
完成了安装。如果不是这样,则需要通过npm install vue-router
进行安装。 - 然后我们出于文件结构清晰的考虑,会有一个
router
文件夹,文件夹下是router的入口index.js
(框架初始化时已经自动生成)。 router/index.js
中生成了路由器Router
实例,其中指定了浏览器地址(path
)到代码(component
)的关联关系,由此完成了引导浏览器根据地址栏输入的地址将项目中对应的代码渲染到浏览器中进行展示的工作。- 然后我们去扩展地址(
path
)跟代码(component
)的关联关系来增加网站能够展示的页面数量。
至此我们接触了vue
路由相关的概念:
- 官方路由包:
vue-router
- 路由文件入口:
src/router/index.js
- 生成的路由器实例:
Router()
- 在项目应用中导入路由
src/main.js[line:10] new Vue(el, router, components, template)
- 在页面中使用路由:
src/App.vue[line:4] <router-view/>
<router-view/>
的作用
<router-view>
就是在页面渲染的时候,通过地址栏的path
在我们指定的路径 -> 代码
的关联关系中找到需要渲染的代码,然后将代码的内容替换到<router-view>
的位置上。通过这一点我们可以进一步理解我们目前看到的页面内容:
- 我们在
HelloWorld
中定义了一些文本和一些超链接,所以渲染时<router-view>
会替换成这些文本和超链接,于是我们便看到浏览器中的内容。
- 当我们输入一个在
路径 -> 代码
关联关系中没有指定的路径,比如/nothing
,我们会看到文本和链接都不见了,取而代之的是一片空白,就可以理解成<router-view>
没有找到要替换的代码,就是空,于是<router-view>
的位置就是一片空白。
- 在
/nothing
页面中,虽然文本和超链接不见了,但是logo图片还在,我们去看这个logo图片代码的位置就可以知道,这是因为logo图片代码是在<router-view>
上方单独的代码,而不是它去替换的内容,所以每个页面都能看到logo图片。
<router-link>
标签
除了<router-view>
标签之外,如果去看官网文档或者其他资料,一般会提到另一个标签叫做<router-link>
。
<router-link>
其实就是替代原生的HTML超链接标签<a>
存在的,写法如下:
<router-link to="/">Go to Home</router-link>
<router-link to="/about">Go to About</router-link>
<router-link>
标签作用
<router-link> text <router-link/>
当然不只是给<a> text </a>
的另一种写法,必然是还有其他好处才会出现。
所以它的好处就是能够使得vue-router
可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。减少页面的重新加载就可以提高网站的性能和用户在浏览和跳转过程中的体验,这才是我们去用<router-link>
代替<a>
所希望得到的。
四、路由用法扩展:更多定制化的路由配置场景
动态路由实现详情页展示
我们在实际开发过程中,一个页面展示的内容布局是不变的,只是页面的数据不同而已,比如:
- 博客网站的博文详情页
- 电商网站的商品详情页
- 视频网站的视频播放页
- …
关于详情页这种只是数据变化的页面,我们的实现方法一般是拿到数据之后将数据展示到对应的位置上。至于数据可以是在页面跳转前将数据传入,常见于我们说的MVC架构中;也可以是从网页请求中获取对应的数据参数,然后进行数据请求得到数据,常见于前后端分离的架构。
如果我们是从网页请求中获取的数据参数,则我们可以常见到如下两种请求方式:
- 参数作为url请求传入:
http://localhost:8080/user?user_id=1
- restful的方式,作为路由的一部分,由路由逻辑按照指定模式去匹配获取:
http://localhost:8080/user/1
如果要实现http://localhost:8080/user/1
这种方式,我们可以可以使用vue-router
的动态路由参数,将router
的配置修改如下:
export default new Router({
mode: "history",
routes: [
{
// 动态字段以冒号开始
path: '/user/:id',
name: 'UserDetail',
component: UserDetail
}
})
除此之外,还有一些其他的常见用法:
-
不同路径指向相同页面:
- 比如
/
和/home
(甚至/index
)都指向HomePage
{ path: '/', component: Homepage, alias: '/home' }
{ path: '/', component: Homepage, alias: ['/home', '/index'] }
- 比如
-
嵌套路由:
- 只替换某些部分的内容,公共内容不变,减少重复代码
/user/:id/profile
:显示用户个人信息/user/:id/posts
:显示用户发布的文章
routes: [
{
path: '/user/:id',
component: User,
children: [
{
// 当 /user/:id/profile 匹配成功
// UserProfile 将被渲染到 User 的 <router-view> 内部
path: '/profile',
component: UserProfile
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 将被渲染到 User 的 <router-view> 内部
path: '/posts',
component: UserPosts
},
],
},
]
- 懒加载:
- 只有当路由被访问的时候才加载对应组件
- 防止页面加载过慢以及构建应用时打包的js包过大
- 不是懒加载的写法:
import HelloWorld from '@/components/HelloWorld'
- 懒加载写法一:
const HelloWorld = ()=>import('@/components/HelloWorld')
- 懒加载写法二(异步):
{ path: '/', name: 'HelloWorld', component: resolve => require(['@/components/HelloWorld'], resolve) }
五、控制路由跳转的API
我们也可以通过在组件中调用Router API来实现路由的跳转、回退等功能。
-
跳转到其他页面:
- API写法:
this.$router.push('/about')
- 等价于
<router-link>
形式:<router-link :to="/about">跳转到About</router-link>
- 等价URL:
/about
- API写法:
-
带参数跳转:
this.$router.push({ path: '/search', query: { keyword: 'vue' } })
- 等价URL:
/search?keyword=vue
-
获取参数:
this.$route.query.keyword // 得到值:vue
-
带锚点hash(#)跳转:
router.push({ path: '/about', hash: '#team' })
- 等价URL:
/about#team
-
使用params跳转
- 可以让参数不显示在URL上,防止一些信息泄露
this.$router.push({ name: 'user', params: { username: 'aki' } })
-
获取params:
this.$router.params.username // 得到值: aki
-
返回上一页:
this.$router.go(-1)
-
后退两页:
this.$router.go(-2)
掌握了以上内容基本就可以解决实际业务开发中的大部分场景,第四部分的API不需要记忆,只需要记住可以通过编写代码逻辑的形式来控制路由即可。
快去试试搭建自己的多页面网站吧~
本系列下一篇文章传送门
写文不易,如果对你有帮助的话,来一波点赞、收藏、关注吧~
文章评论