用过Vue,Vue-Router的同学在获取数据的时候,肯定遇到过路由切换后,数据没有重新获取的情况。
官方文档中给出来两种解决方案:
导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。
导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。
首先给出官网的例子:
<template>
<div class="post">
<div class="loading" v-if="loading">
Loading...
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<div v-if="post" class="content">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
</div>
</template>export default {
data () {
return {
loading: false,
post: null,
error: null
}
},
created () {
// 组件创建完后获取数据,
// 此时 data 已经被 observed 了
this.fetchData()
},
watch: {
// 如果路由有变化,会再次执行该方法
'$route': 'fetchData'
},
methods: {
fetchData () {
this.error = this.post = null
this.loading = true
// replace getPost with your data fetching util / API wrapper
getPost(this.$route.params.id, (err, post) => {
this.loading = false
if (err) {
this.error = err.toString()
} else {
this.post = post
}
})
}
}
}vue-router的路由加载是相同的的组件会重复利用,节约性能开销,当路径的变化时,会利用其他的手段来监听路参数的变化,如watch属性。上述代码中,在component的created钩子函数中获取数据,然后在watch属性中监听路由$route的参数的变化,当路由切换后,根据id再次获取数据。这个方法可以有两种不同的另类实现方式。
第一种方式:
export default {
data () {
return {
loading: false,
post: null,
error: null
}
},
watch: {
// 如果路由有变化,会再次执行该方法
'$route': {
handler: 'fetchData',
immediate: true
}
},
methods: {
fetchData () {
this.error = this.post = null
this.loading = true
// replace getPost with your data fetching util / API wrapper
getPost(this.$route.params.id, (err, post) => {
//
})
}
}
}watch监听的$route变成了一个对象,handler是调用的方法,immediate则表示在组件加载完成后立即执行handler的方法,并且可以删除created生命周期函数。
第一种方式已经稍微简化了代码。但是其实还有另外一种的方法。
export default {
data () {
return {
loading: false,
post: null,
error: null
}
},
created() {
this.fetchData()
}
methods: {
fetchData () {
this.loading = true
// replace getPost with your data fetching util / API wrapper
getPost(this.$route.params.id, (err, post) => {
//
})
}
}
}
<router-view :key="$route.fullPath"></router-view>上述代码的trick是在<router-view />组件添加一个keyprop,值为$route.fullPath。当key变化时间,组件会删除再重新创建,然后执行created钩子函数。这个方法会稍微影响应用的性能,但是数据加载不会出bug。