数据获取
有的时候,进入某个路由以后,我们需要从服务端获取数据,比如 /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>