Vue-Router
首先了解两个概念:单页应用和路由。
安装、配置 vue-router
安装
对应vue工程,我们使用命令行进行安装:
npm install vue-router
// 或者
yarn add vue-router
配置
这些配置可以写在src/main.js
文件中,不过当配置过多时,建议写在src/router/indes.js
中。
// 0. 导入 Vue 和 VueRouter,要调用 Vue.use(VueRouter)
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
import Foo from "./views/Foo.vue";
import Bar from "./views/Bar.vue";
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')
路由的使用
主要的两个标签
<router-link></router-link>
和 <router-view><router-view>
<template>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<!-- App.vue 中的 <router-view></router-view> 是路由的最高级出口 -->
<router-view> <!-- 这里面会显示main.js中配置的组件 --!> </router-view>
</div>
</template>
导入组件的写法
导入组件除了上面import
之外,还可以直接在router
中书写,同时还可以为路由命名:
const routes = [
{ path: '/foo',
name: 'fooName',
component: () => import('./views/Foo.vue')
}
];
通过命名进行跳转:
<!-- to 的值是一个对象而不是字符串,所以要在 to 前加 : -->
<router-link :to="{name: 'fooName'}">Go to Foo</router-link>
路由布局管理(嵌套)
- 在组件中配合路由使用
<router-view>
;
App.vue中:
<template>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/album/list">Go to Album List</router-link>
|
<router-link to="/album/add">Go to Album Add</router-link>
</p>
<!-- 路由匹配到的组件将渲染在这里 -->
<!-- 在本例中为 Album.vue 组件 -->
<router-view></router-view>
</div>
</template>
Album.vue中:
<template>
<div id="album">
<div class="banner">banner</div>
<!-- 路由匹配到的组件将渲染在这里 -->
<!-- 在本例中为 List.vue 组件或 Add.vue 组件 -->
<router-view></router-view>
</div>
</template>
- 定义嵌套路由
// 0. 导入 Album、List、Add 三个组件
const routes = [
{
path: '/album',
component: Album,
// children 属性可以用来配置下一级路由(子路由)
children: [
{ path: 'list', component: List },
{ path: 'add', component: Add }
]
}
];
- 需要注意的是:如果希望用路径
"/album/list"
对应在 Album.vue 中渲染出 list,那么子路由中的 path 有两种写法:path: 'list'
或者path: '/album/list'
,但是/list
这样的写法是错误的,因为以反斜杠开头的嵌套路径会被当成根路径,那么 List.vue 会被直接渲染到 App.vue 中的<router-view>
。 - 空的子路由:基于上面的路由配置,如果想在路径为
/album
时仍想在功能渲染些什么,则可以使用空的子路由:
// 0. 导入 Album、List、Add、Empty 三个组件
const routes = [
{
path: '/album',
component: Album,
// children 属性可以用来配置下一级路由(子路由)
children: [
// 空的子路由
{ path: '', component: Empty },
{ path: 'list', component: List },
{ path: 'add', component: Add }
]
}
];
动态路由
动态路由
动态路由即符合某模式的多个路径映射到同一个组件,具体写法为:
import User from "./views/User.vue";
const routes = [
// id 就是路径参数,前面要加冒号
{ path: '/user/:id', component: User }
]
当URL匹配到路由中的一个路径时,参数id
会被设置到this.$router.params
中,可以在组件中读取:
<template>
<div>user id: {{ $route.params.id }}</div>
</template>
捕获404页面
当用户输入的URL不属于我们注册的任何一个路由时,我们常需要用404 NotFound
组件渲染,这里我们使用通配符*
匹配任意路径:
import NotFound from "./views/NotFound.vue";
const routes = [
{
// 会匹配所有路径
path: '*',
component: NotFound
}
]
需要注意的是:使用通配符时应该将其放在路由的最后,因为路由的匹配通常时按照注册顺序进行匹配的,如果
path: '*'
放在最前面,那么所有的页面都会因为先匹配搭配通配符而都被渲染为404 NotFound
组件。
获取匹配到的路径值
当使用一个通配符时,$router.params
中会自动添加一个名为pathMatch
的参数,它包含了URL通过通配符匹配到的部分,例如:http://localhost:8081/non-existing/file
这个网站被匹配到的内容
this.$route.params.pathMatch // '/non-existing/file'
页面跳转(router.push)
一、router.push
的参数是字符串路径时
router.push('user')
router.push('/user')
二、router.push
的参数为描述地址的对象
// 0.这种写法和字符串类型的参数一样
router.push({ path: 'home' })
// 1.命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 2.带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
如果使用 path 进行页面跳转时,写 params 进行传参时会被忽略:
// params 会被忽
router.push({ path: 'user', params: { userId: '123' }})
//应该这样写:
router.push({ path: 'user/123'})
使用$router
可以获取当前路由的各个参数:
// $route
{
// 路由名称
name: "user",
meta: {},
// 路由path
path: "/user/123",
// 网页位置指定标识符
hash: "#abc",
// window.location.search
query: {name: "userName"},
// 路径参数 user/:userId
params: {userId: "123"},
fullPath: "/user/123?name=userName#abc"
}
重定向和别名
别名
顾名思义,即一个路由可以由两个名字来指向它,下面的代码中访问/a
或者是/b
都会渲染A:
const routes: [
// 定义 alias 属性
{ path: '/a', alias: '/b', component: A }
];
重定向
若路由/a
重定向到/b
,即访问/a
时,url会自动跳转到/b
,然后匹配路由/b
:
const routes: [
// 定义 redirect 属性,将 /a 重定向到 /b
{ path: '/a', redirect: '/b' }
]
一般情况我们希望把localhost:8080/layout/home
表示为localhost:8080
,则可以使用上面的别名和重定向来完成:
const routes: [
{
path: '/layout',
// 别名定为 /
alias: '/',
// 重定向到 /home
redirect: '/home',
component: ()=> import('@/pages/nest/Layout.vue'),
children: [
{ path: 'home', component: Home },
{ path: 'courseall', component: CourseAll },
{ path: 'coursedetail/:courseId', component: CourseDetail }
]
}
];
监听路由
监听路由即监听$router
的变化,需要用到watch
,其中的to
就是变化后的路由,from
就是变化前的路由:
watch: {
$route(to,from){
console.log(to, from);
}
}
为某个标签添加额外的类名:
:class="{active: tab.active}"
,即如果 tab.active 的值为真,则为该标签添加类名 active。
<script>
export default {
watch: {
$route(to, from) {
// 路由变化了就执行更新样式的方法
this.updateTab();
console.log(to, from);
}
},
methods: {
// 为该标签添加点击事件,使用router实例改变路径参数
changeTab(type) {
this.$router.push({ query: { type: type } });
},
// 更新样式的方法
updateTab() {
// 处理特殊情况,即初始状态时没有传入参数则不执行任何操作
if (!this.$route.query.type) return;
this.tabList.map(menu => {
// 当标签的type等于路径参数的type时,active为true
menu.active = menu.type === this.$route.query.type;
});
}
}
};
</script>
网络请求 async 与 await
在Js中我们使用fetch
请求数据并获得一个Promise
对象,其特点就是无等待,所以想对返回的数据进行处理时,只能在then
平铺回调的方式中进行处理:
fetch(
'https://www.fastmock.site/mock/b73a1b9229212a9a3749e046b1e70285/f4/f4-11-1-1'
)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
“异步”async 和 “等待异步”await
异步async
用于声明一个异步函数,其返回的结果是一个Promise
对象;关键字await
用于等待一个异步方法执行的完成,他会阻塞后面的代码,等着Promise
对象 resolve*,然后得到 resolve 的结果,作为await
表达式的值:
async function asyncFn() {
return {
"company": "优课达",
"slogan": "学的比别人好一点"
};
}
async function getAsyncFn() {
const result = await asyncFn();
console.log(result);
}
getAsyncFn();
需要注意的是:关键字
await
不能在普通的函数中使用,只能在async
声明的函数中使用!想要了解关于Promise
更多的信息,请看这个文档
多个请求并发执行 Promise.all
async function asyncFn1() {
return "优课达";
}
async function asyncFn2() {
return "学的比别人好一点";
}
async function getAsyncFn() {
// Promise.all()参数是一个函数数组
const result = await Promise.all([asyncFn1(), asyncFn2()]);
console.log(result);
}
getAsyncFn();
在 vue 中请求数据
使用 async 和 await 请求数据
<script>
export default {
data: function() {
return {
courseList: []
};
},
async mounted() {
// 在生命周期 mounted 中调用获取课程信息的方法
await this.queryAllCourse();
},
methods: {
// 在 methods 对象中定义一个 async 异步函数
async queryAllCourse() {
// 在 fetch 中传入接口地址
const res = await fetch('https://www.fastmock.site/mock/2c5613db3f13a5c02f552c9bb7e6620b/f5/api/queryallcourse');
// 将文本体解析为 JSON 格式的promise对象
const myJson = await res.json();
// 获取返回数据中的 data 赋值给 courseList
this.courseList = myJson.data;
}
}
}
</script>
给 api 传参
<script>
export default {
data: function() {
return {
course: []
};
},
async mounted() {
await this.getCourse();
},
methods: {
async getCourse() {
// 从路径中获取课程 id
const courseId = this.$route.params.courseId
// 在接口地址后传入参数 id
const res = await fetch('https://www.fastmock.site/mock/2c5613db3f13a5c02f552c9bb7e6620b/f5/api/getcourse?id=' + courseId);
const myJson = await res.json();
this.course = myJson.data;
}
}
}
</script>