Vuejs路由
一:vue-cli2创建项目
F:\WWWROOT\vuepro>vue init webpack testrouter
F:\WWWROOT\vuepro>cd testrouter
F:\WWWROOT\vuepro\testrouter>npm run dev
二:前端路由
随着Ajax的出现, 有了前后端分离的开发模式。后端只提供API来返回数据, 前端通过Ajax获取数据, 并且可以通过JavaScript将数据渲染到页面中。这样做最大的优点就是前后端责任的清晰, 后端专注于数据上, 前端专注于交互和可视化上。并且当移动端(iOS/Android)出现后, 后端不需要进行任何处理, 依然使用之前的一套API即可。目前很多的网站依然采用这种模式开发。
单页面富应用阶段:其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由。也就是前端来维护一套路由规则。
前端路由的核心是什么呢?改变URL,但是页面不进行整体的刷新。
2.1 URL的hash
URL发生了改变,但是整个页面不会被刷新
2.2 HTML的history模式
history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面
history.pushState()跳转后URL不能返回
history.replaceState()跳转后可以返回
三:vue-router
如果在使用脚手架创建项目时没有安装路由,那么使用下面的命令安装:
npm install vue-router --save
在src目录下创建router目录,然后在router目录创建index.js文件:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
// 这里写路由规则
]
const router = new VueRouter({
routes
})
export default router
在main.js文件中导入router
import Vue from 'vue'
import App from './App'
import router from './router' # 默认会找到/router/index.js文件
Vue.config.productionTip = false
new Vue({
el: '#app',
router, # 注册路由
render: h => h(App)
})
3.1 使用vue-router
使用vue-router的步骤:
- 第一步: 创建路由组件
- 第二步: 配置路由映射: 组件和路径映射关系
- 第三步: 使用路由: 通过router-link和router-view
首先在components目录下创建两个组件:Home.vue, About.vue,然后编写路由规则:
import Home from '../components/Home'
import About from '../components/About'
Vue.use(VueRouter)
const routes = [
// 这里写路由规则
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
在App.vue文件中通过router-link与router-view让其最终渲染到页面
<template>
<div id="app">
<router-link to="/home">首页</router-link> # router-link默认最终会渲染成a标签
<router-link to="/about">关于</router-link>
<router-view></router-view> # router-view的作用是让路由对应的组件显示在哪里,写在router-link下面,那么组件内容显示在下方,反之显示在上方
</div>
</template>
router-link: 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个a标签.
router-view: 该标签会根据当前的路径, 动态渲染出不同的组件.
网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和router-view处于同一个等级.
在路由切换时, 切换的是router-view挂载的组件, 其他内容不会发生改变.
3.2 设置默认首页
const routes = [
{
path: '', # 也可以写成:path:'/',
redirect: '/home' # 重定向到url /home
},
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
3.3 修改路由的显示方式
我们前面说过改变路径的方式有两种:
- URL的hash(默认的路由方式)
- HTML5的history
默认情况下, 路径的改变使用的URL的hash。如果希望使用HTML5的history模式, 非常简单, 进行如下配置即可
const router = new VueRouter({
routes,
mode: 'history'
})
3.4 router-link
在前面的router-link中, 我们只是使用了一个属性: to, 用于指定跳转的路径。
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即可.
<router-link to='/home' tag='li' replace> # 渲染成li标签
3.5 通过代码跳转路由
<template>
<div id="app">
<button @click="homeClick">首页</button>
<button @click="aboutClick">关于</button>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
homeClick() {
// this.$router.push('/home')
this.$router.replace('/home')
},
aboutClick() {
this.$router.push('/about')
}
}
}
</script>
3.6 动态路由
在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:
- /user/aaaa或/user/bbbb
- 除了有前面的/user之外,后面还跟上了用户的ID
- 这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)。
App.vue路由展示:
<template>
<div id="app">
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
<router-link :to="'/user/' + username">User</router-link> # 动态绑定to属性,因为username是动态获取(假设)的数据
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
username: 'lisi'
}
}
}
</script>
因为要传递参数,所以路由规则的写法如下 (router/index.js):
{
path: '/user/:username',
component: User
}
路由组件 user的内容如下:
<template>
<div>
<h2>User page</h2>
<h2>{{username}}</h2>
// <h2>{{$route.params.username}}</h2>
</div>
</template>
<script>
export default {
name: "User",
computed: {
username() {
// this.$route:哪个路由处于活跃状态,this.$route就是谁
return this.$route.params.username # 获取路由中的username参数
}
}
}
</script>
$route和$router是有区别的
$router为VueRouter实例,想要导航到不同URL,则使用$router.push方法
$route为当前router跳转对象里面可以获取name、path、query、params等
3.7 路由的懒加载
官方解释:当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
官方在说什么呢?
首先, 我们知道路由中通常会定义很多不同的页面,这个页面最后被打包在哪里呢? 一般情况下, 是放在一个js文件中。但是, 页面这么多放在一个js文件中, 必然会造成这个页面非常的大。如果我们一次性从服务器请求下来这个页面, 可能需要花费一定的时间, 甚至用户的电脑上还出现了短暂空白的情况。那么如何避免这种情况呢? 使用路由懒加载就可以了。
路由懒加载做了什么?路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块。只有在这个路由被访问到的时候, 才加载对应的组件。
路由懒加载后的效果如下:
const Home = () => import('../components/Home')
const About = () => import('../components/About')
const User = () => import('../components/User')
3.8 路由的嵌套
嵌套路由是一个很常见的功能:
比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容.
一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件.
路径和组件的关系如下:
实现嵌套路由有两个步骤:
- 创建对应的子组件, 并且在路由映射中配置对应的子路由.
- 在组件内部使用router-view标签.
路由规则如下:
{
path: '/home',
component: Home,
children: [
{
path: '',
redirect: 'news'
},
{
path: 'news', # 前面不需要加/,vuejs会自动拼接
component: HomeNews,
},
{
path: 'message',
component: HomeMessage
}
]
},
因为是Home路由下的子路由,所以两个子组件都在Home组件下展示:
<template>
<div>
<h2>Home</h2>
<router-link to="/home/news">News</router-link> # 这里必须要写全路径
<router-link to="/home/message">Message</router-link>
<router-view></router-view>
</div>
</template>
展示效果如下图:
3.9 路由传参
传递参数主要有两种类型: params和query
params的类型:
- 配置路由格式: /router/:id
- 传递的方式: 在path后面跟上对应的值
- 传递后形成的路径: /router/123, /router/abc
query的类型:
- 配置路由格式: /router, 也就是普通配置
- 传递的方式: 对象中使用query的key作为传递方式
- 传递后形成的路径: /router?id=123, /router?id=abc
如何使用它们呢? 也有两种方式: router-link的方式和JavaScript代码方式
传递参数方式一: router-link
路由规则:
{
path: '/profile',
component: Profile
}
路由展示:
<template>
<div id="app">
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
<router-link :to="{path: '/profile', query: {name: 'andy', age: 18}}">Profile</router-link>
<router-view></router-view>
</div>
接收参数:
<template>
<div>
<h2>Profile page</h2>
<h2>{{$route.query.name}}</h2>
<h2>{{$route.query.age}}</h2>
</div>
</template>
传递参数方式二: JavaScript代码
# App.vue
<template>
<div id="app">
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
<!-- <router-link :to="{path: '/profile', query: {name: 'andy', age: 18}}">Profile</router-link>-->
<button @click="profileClick">档案</button>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
username: 'lisi'
}
},
methods: {
profileClick() {
this.$router.push({
path: '/profile',
query: {
name: 'Andy',
age: 17
}
})
}
}
}
</script>
3.10 导航守卫
我们来考虑一个需求: 在一个SPA应用中, 如何改变网页的标题呢?
网页标题是通过title来显示的, 但是SPA只有一个固定的HTML, 切换不同的页面时, 标题并不会改变。但是我们可以通过JavaScript来修改title的内容.window.document.title = ‘新的标题’。
那么在Vue项目中, 在哪里修改? 什么时候修改比较合适呢?
普通的修改方式:
我们比较容易想到的修改标题的位置是每一个路由对应的组件.vue文件中,通过mounted声明周期函数, 执行对应的代码进行修改即可。但是当页面比较多时, 这种方式不容易维护(因为需要在多个页面执行类似的代码).
有没有更好的办法呢? 使用导航守卫即可.
什么是导航守卫?
vue-router提供的导航守卫主要用来监听路由的进入和离开的.
vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发。
Vue.use(VueRouter)
const routes = [
{
path: '',
redirect: '/home'
},
{
path: '/home',
component: Home,
meta: { # meta元数据,描述数据的数据
title: '首页'
},
children: [
{
path: '',
redirect: 'news'
},
{
path: 'news',
component: HomeNews,
},
{
path: 'message',
component: HomeMessage
}
]
},
{
path: '/about',
component: About,
meta: {
title: '关于我们'
},
},
{
path: '/profile',
component: Profile,
meta: {
title: '人个中心'
},
}
]
const router = new VueRouter({
routes,
mode: 'history'
})
router.beforeEach((to, from, next) => {
document.title = to.matched[0].meta.title
console.log(to);
next() # next函数必须要调用
})
export default router
导航钩子的三个参数解析:
- to: 即将要进入的目标的路由对象.
- from: 当前导航即将要离开的路由对象.
- next: 调用该方法后, 才能进入下一个钩子.
补充一:如果是后置钩子, 也就是afterEach, 不需要主动调用next()函数.
补充二:上面我们使用的导航守卫, 被称之为全局守卫.
- 路由独享的守卫.
- 组件内的守卫.
3.11 keep-alive
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
它们有两个非常重要的属性:
- include - 字符串或正则表达,只有匹配的组件会被缓存
- exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
<template>
<div id="app">
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
<button @click="profileClick">档案</button>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>