Vue 0基础学习路线(23)—— 图解深度详述vue的路由数据获取和导航完成之后获取与导航完成之前获取和详述nProgress进度条第三方库的使用及详细案例(附详细案例代码解析过程及版本迭代过程)

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模板的逻辑,如果errortrue,显示没有该商品信息

判断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: branch06

commit 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: branch06

commit 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: branch06

commit 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: branch06

commit description:a2.25(nprogress使用)

tag:a2.25

note:以上放在路由里面的全局守卫当中,以上看具体的需求,如果仅仅是点击详情跳转需要的话,我们就把它放入路由独享守卫即可。

考虑到在blog中不好体现代码更改的位置,小迪才用github托管代码,大家可以查看github,看到详细版本修改过程,搭配博客学习。



(后续待补充)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值