文章目录
1. 重点提炼
- 数据获取
- 导航完成之后获取
- 导航完成之前获取
- nprogress
2. 引言
特别是在做移动端的时候,大部分都是单页面应用,在后端再把延时调回来到3s
,方便使用。在线上发布项目后,从后端获取数据必然存在着延迟,即loading
状态。
其实一般开发下,这里的数据显示有两种形式 =>
-
第一种点击后先跳页面再请求数据然后显示数据
-
第二种是点击后不跳页面等待数据请求完毕后再跳页面
其实大部分应用,还是导航完成之前获取数据 => 程序猿们经常使用的Github
就是一个典型的例子(加载的时候,还有进度条提示)。
3. 路由数据获取
有的时候,进入某个路由以后,我们需要从服务端获取数据,比如 /item/:itemId
,通常,我们有两种方式来实现
- 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据,在数据获取期间显示加载中之类的 loading 提示
- 导航完成之前获取: 导航完成之前,在路由进入的守卫中获取数据,在数据获取成功以后执行导航。
这两种方式都没有任何问题(对错、好坏),自行选择
4. 导航完成之后获取
<template>
<div>
<template v-if="loading">
Loading......
</template>
<template v-if="hasError">
<h2>没有该商品信息</h2>
</template>
<template v-if="item">
<h2>商品详情 - {
{item.name}}</h2>
<dt>ID</dt>
<dd>{
{item.id}}</dd>
<dt>名称</dt>
<dd>{
{item.name}}</dd>
<dt>价格</dt>
<dd>{
{item.price|RMB}}</dd>
</template>
</div>
</template>
<script>
import axios from 'axios';
import {
RMB} from '@/filters/RMB';
export default {
name: 'item',
props: ['itemId'],
data() {
return {
loading: false,
hasError: false,
item: null
}
},
filters: {
RMB
},
watch: {
itemId() {
this.getItem();
}
},
created() {
this.getItem();
},
methods: {
getItem() {
this.loading = true;
if (this.itemId) {
axios({
url: `/api/item/${
this.itemId}`
}).then(res => {
this.item = res.data;
}).catch(err=>this.hasError=true).then(_=>{
this.loading = false;
});
}
}
}
}
</script>
5. 导航完成之前获取
// item.vue
<script>
export default {
...,
beforeRouteEnter( to, from, next ) {
console.log('开始');
return axios({
url: `/api/item/${
to.params.itemId}`
}).then(res => {
// 注意 beforeRouteEnter 还不能获取组件实例
next(vm => {
vm.item = res.data;
});
}).catch(err=>{
next(vm => {
vm.hasError = true;
});
});
},
beforeRouteUpdate(to, from, next) {
return axios({
url: `/api/item/${
to.params.itemId}`
}).then(res => {
// 注意 beforeRouteEnter 还不能获取组件实例
this.item = res.data;
}).catch(err=>{
this.hasError = true;
});
}
}
</script>
6. 实例
6.1 example01
咱们之前做的,进入页面因为数据还没请求完成,页面显示没有该商品信息
。这种提示不太准确,应该为加载中
。请求数据出了错之后,再显示没有该商品信息
。 => 再把逻辑优化一下
Detail
组件中请求数据赋给的rs
是可以获取错误状态的,我们可以用try...catch
捕获异常。在data
中设置一个error
属性(默认为false
),如果以异常发生,设置为true
即可。
改一些页面html
模板的逻辑,如果error
为true
,显示没有该商品信息
。
判断item
属性为空,应该显示为加载中
。
\app\src\views\Detail.vue
<template>
<div>
<template v-if="error">
<h2>没有该商品信息</h2>
</template>
<template v-else>
<template v-if="item">
<h2>商品详情 - {
{item.name}}</h2>
<dt>ID</dt>
<dd>{
{item.id}}</dd>
<dt>名称</dt>
<dd>{
{item.name}}</dd>
<dt>价格</dt>
<dd>{
{item.price|RMB}}</dd>
</template>
<template v-else>
<h2>加载中……</h2>
</template>
</template>
</div>
</template>
<script>
import * as apis from '@/apis'
import {
RMB} from "@/filters/RMB";
export default {
name: "Detail",
props: ['id','a'],
data() {
return {
item: null,
error: false
}
},
filters: {
RMB
},
async created() {
console.log(this);
let id = this.id;
try {
let rs = await apis.getItem(id);
this.item = rs.data;
} catch (e) {
this.error = true;
}
}
}
</script>
<style scoped>
</style>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a2.22
Branch: branch06commit description:a2.22(example01——优化提示用户loading和获取出错页面)
tag:a2.22
6.2 example02
实现导航完成之前获取信息。
6.2.1 example02-1
这个时候就需要用到路由生命周期beforeRouterEnter
(在Detail
组件上添加) => 导航进入的时候,我们知道有一个问题是,在这里不调用next
方法的话,就导航挂在里面不能往下继续了。
beforeRouteEnter(to, from, next) {
}
我们点击之后,没有任何反应,根本跳转不到详情页。
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a2.23
Branch: branch06commit description:a2.23(example02-1——beforeRouteEnter停挂)
tag:a2.23
6.2.2 example02-2
beforeRouteEnter
优先组件执行之前调用,因此不执行next
,后面就无法跳转了。
导航完成之前获取信息的工作就在这里做了,我们不在created
的生命周期(组件创建之后)发送请求了,
把请求移到beforeRouteEnter
中,但是就得考虑一些问题了,首先this
从哪里来?肯定是获取不到的,组件都没创建出来,this
肯定也不存在了。
async created() {
console.log(this);
let id = this.id;
try {
let rs = await apis.getItem(id);
this.item = rs.data;
} catch (e) {
this.error = true;
}
},
this.id
=> 如果是路由过来的话,直接从目标点to
对象下取参数即可。
this.item
=> 通过next
的回调函数中的vm
参数(相当于this
)获取
出错的时候,同理
async beforeRouteEnter(to, from, next) {
try {
let id = to.params.id;
let rs = await apis.getItem(id);
// this.item = rs.data;
next( vm => {
vm.item = rs.data;
} );
} catch (e) {
// this.error = true;
next( vm => {
vm.error = true;
} );
}
}
完整代码
<template>
<div>
<template v-if="error">
<h2>没有该商品信息</h2>
</template>
<template v-else>
<template v-if="item">
<h2>商品详情 - {
{item.name}}</h2>
<dt>ID</dt>
<dd>{
{item.id}}</dd>
<dt>名称</dt>
<dd>{
{item.name}}</dd>
<dt>价格</dt>
<dd>{
{item.price|RMB}}</dd>
</template>
</template>
</div>
</template>
<script>
import * as apis from '@/apis'
import {
RMB} from "@/filters/RMB";
export default {
name: "Detail",
props: ['id','a'],
data() {
return {
item: null,
error: false
}
},
filters: {
RMB
},
async beforeRouteEnter(to, from, next) {
try {
let id = to.params.id;
let rs = await apis.getItem(id);
// this.item = rs.data;
next( vm => {
console.log(vm)
vm.item = rs.data;
} );
} catch (e) {
// this.error = true;
next( vm => {
vm.error = true;
} );
}
}
}
</script>
<style scoped>
</style>
按照导航完成之前获取信息,页面显示的加载中
,就不需要了。
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a2.24
Branch: branch06commit description:a2.24(example02-2——实现导航完成之前获取信息)
tag:a2.24
7. 扩展 - nprogress
http://ricostacruz.com/nprogress/
7.1 如何使用
这个库提供了一个NProgress
的对象,底下提供了四个方法 =>
NProgress .start
() -显示进度栏
按照一定的频率慢慢加载进度条
NProgress
.set(0.4)
- 设置百分比
一下就到40%
NProgress
.inc()
— 一点点递增
NProgress
.done()
- 立刻完成进度
7.2 安装
npm i nprogress
// OR
yarn add nprogress
配合 router 全局守卫
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
const router = new Router({
//...
});
router.beforeEach((to, from, next) => {
NProgress.start()
next()
})
router.afterEach((to, from, next) => {
NProgress.done()
})
export default router
7.3 实例
安装
yarn add nprogress
安装后在哪里使用呢?
实际跳转的时候就可以使用,我们之前看到的github
官网跳转的时候,就有进度条。
每次路由跳转都需要使用,我们应该将其放在路由里面的全局守卫
当中。
router.beforeEach
=> NProgress.start()
至于加载多少就不管了, 它实际是假进度条。
router.afterEach
=> NProgress.done();
导航结束后,进度条到头就完事了。
用的时候需要引入两个头文件
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
router.beforeEach((to, from, next) => {
NProgress.start();
// next();
// id为1代表登录,否则为0代表没登录
if (user.id === 0 && to.name === 'user') {
next({
name: 'login'});
} else {
next();
}
});
router.afterEach((to, from, next) => {
NProgress.done();
})
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a2.25
Branch: branch06commit description:a2.25(nprogress使用)
tag:a2.25
note:
以上放在路由里面的全局守卫当中,以上看具体的需求,如果仅仅是点击详情跳转需要的话,我们就把它放入路由独享守卫即可。
考虑到在blog中不好体现代码更改的位置,小迪才用github托管代码,大家可以查看github,看到详细版本修改过程,搭配博客学习。
(后续待补充)