数据获取

有的时候,进入某个路由以后,我们需要从服务端获取数据,比如 /item/:itemId ,通常,我们有两种方式来实现

  • 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子(生命周期方法如created)中获取数据,在数据获取期间显示加载中之类的 loading 提示
  • 导航完成之前获取: 导航完成之前,在路由进入的守卫中获取数据,在数据获取成功以后执行导航。

这两种方式都没有任何问题(对错、好坏),自行选择

一、导航完成之后获取

注意:

loading和hasError初始值都是false;

NotFound组件的引入和使用;

<template>
  <div>
    <!-- 导航完成前先显示loading页面 -->
    <template v-if="loading">loading......</template>
    <!-- 如果发生错误显示错误页面 -->
    <template v-if="hasError">
      <NotFound></NotFound>
    </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>
    <!-- <template v-else>
      <h2>没有该商品信息</h2>
    </template> -->
  </div>
</template>

<script>
import axios from "axios";
import RMB from "@/filter/RMB";
import NotFound from "./NotFound.vue";

export default {
  name: "Item",
  // 注册过滤器
  filters: {
    RMB
  },
  components:{
    NotFound
  },
  // 因为原来的Item.vue组件是通过 `this.$route.params.id` 来接收 `id` 的,但是作为功能组件 `id` 需要通过prop来传入,此时需要对Item.vue组件进行改造
  props: ["id"],
  data() {
    return {
      item: null,
      loading: false,
      hasError: false
    };
  },
  created() {
    // 通过动态路由和拼接字符串形式都需要通过 路由对象 获取id的值
    // const {id} = this.$route.params;
    this.getItem();
  },
  // 在鼠标悬浮时,Item发生变化,也需要获取一次Item商品信息
  watch: {
    id() {
      this.getItem();
    }
  },
  // 点击和鼠标悬浮时都需要获取商品信息
  methods: {
    getItem() {
      this.loading = true;
      if (this.id > 0) {
        axios({
          // 详情页:id占位符
          // url: "/api/item/"+id
          //  使用params传参
          //  url: `/api/item/${id}`
          // 使用路由组件props传参后,必须使用this.id才能获取到
          url: `/api/item/${this.id}`
        })
          .then(res => {
            this.item = res.data;
            this.loading = false;
          })
          .catch(err => this.hasError = true)
          .then(_ => {
            // 如果发现错误则会显示错误页面不再显示loading页面
            this.loading = false;
          });
      }
    }
  }
};
</script>

<style>
</style>

二、导航完成之前获取

<template>
  <div>
    <!-- 导航完成前先显示loading页面 -->
    <template v-if="loading">loading......</template>
    <!-- 如果发生错误显示错误页面 -->
    <template v-if="hasError">
      <NotFound></NotFound>
    </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>
    <!-- <template v-else>
      <h2>没有该商品信息</h2>
    </template> -->
  </div>
</template>

<script>
import axios from "axios";
import RMB from "@/filter/RMB";
import NotFound from "./NotFound.vue";

export default {
  name: "Item",
  // 注册过滤器
  filters: {
    RMB
  },
  components:{
    NotFound
  },
  // 因为原来的Item.vue组件是通过 `this.$route.params.id` 来接收 `id` 的,但是作为功能组件 `id` 需要通过prop来传入,此时需要对Item.vue组件进行改造
  props: ["id"],
  data() {
    return {
      item: null,
      loading: false,
      hasError: false
    };
  },


  // 导航完成之前获取数据
  // created() {
  //   // 通过动态路由和拼接字符串形式都需要通过 路由对象 获取id的值
  //   // const {id} = this.$route.params;
  //   this.getItem();
  // },
  // 在鼠标悬浮时,Item发生变化,也需要获取一次Item商品信息
  watch: {
    id() {
      this.getItem();
    }
  },
  beforeRouteEnter(to, from, next){
    console.log("进入组件前获取数据。。。。。");
    // 组件生成前获取不了this设置不了loading的值
    //  this.loading = true;
      if (to.params.id > 0) {
        return axios({
          url: `/api/item/${to.params.id}`
        })
          .then(res => {
            // 注意 beforeRouteEnter 还不能获取组件实例
            next(vm=>{
              vm.item = res.data;
              // vm.loading = false;
            });
          })
          .catch(err => {
            next(vm=>{
              vm.hasError = true;
            });
          })
          .then(_ => {
            // 如果发现错误则会显示错误页面不再显示loading页面
            next(vm=>{
              // vm.loading = false;
            });
          });
      }
  },
  beforeRouteUpdate(to, from, next){
    console.log("组件更新后。。。。");    
    // beforeRouteUpdate组件已经完成可以获取this 
     this.loading = true;
      if (to.params.id > 0) {
        return axios({
          url: `/api/item/${to.params.id}`
        })
          .then(res => {
            this.item = res.data;
            this.loading = false;
          })
          .catch(err => this.hasError = true)
          .then(_ => {
            // 如果发现错误则会显示错误页面不再显示loading页面
            this.loading = false;
          });
      }
  },

  // 点击和鼠标悬浮时都需要获取商品信息
  methods: {
    getItem() {
      this.loading = true;
      if (this.id > 0) {
        axios({
          url: `/api/item/${this.id}`
        })
          .then(res => {
            this.item = res.data;
            this.loading = false;
          })
          .catch(err => this.hasError = true)
          .then(_ => {
            // 如果发现错误则会显示错误页面不再显示loading页面
            this.loading = false;
          });
      }
    },
  }
};
</script>