# 数据加载的问题
在使用了mock.js进行数据填充之后,通过axios发送数据请求,而mock进行监听和拦截,并且根据请求发送数据
但是在原本的代码结构中,出现了一些情况。
# 原代码展示
# vue/js
这里是原 App.vue 和 store中的部分代码
//... 代码省略
export default {
//...
created () {
console.log('app.vue.created 执行了')
axios.get('/user/allUsers')
.then(res => {
this.$store.commit('getAlluUsers', res.data.list)
})
.catch(err => {
console.log(err)
})
// ...后面类似,在此省略
}
}
// store.js
//...
state: {
allUsers: []
},
mutataions: {
getAllUsers (state, allUsers) {
state.allUsersReady = true
console.log('the allUsers is ready')
}
}
这里是其他几个vue文件中的部分代码
// homePage.vue
// ...
created () {
console.log('homePage.vue.created执行了')
},
mounted () {
console.log('homePage.vue.mounted执行了')
},
// homePageMain.vue
// ...
created () {
console.log('homePageMain.vue.created执行了')
},
mounted () {
console.log('homePageMain.vue.mounted执行了')
},
// carseAndComTab.vue
// ...
mounted () {
console.log('carseAndComTab.vue.mounted执行了')
// 调用 store 中的数据,这里省略
}
# html
在html代码结构上如下:
<!-- App.vue -->
<div>
<router-view></router-view> <!-- 这里是载入homePage.vue,后见路由结构 -->
</div>
<!-- homePage.vue -->
<!-- ...省略 -->
<div>
<router-view></router-view> <!-- 这里是载入homePageMain.vue -->
</div>
<!-- homePageMain.vue -->
<div>
<carseAndComTab></carseAndComTab> <!-- 这里是carseAndComTab组件-->
</div>
# 路由
路由结构如下:
// ...
routers: [
{
path: '/',
redirect: '/home' //默认跳转到/home
},
{
path: 'home',
component: homePage,
children: [
{
path: '',
component: homePageMain
},
// ...
]
}
]
# 问题描述
到这里,得讲一下这样子出现的一个问题了。
按照期望,我们希望得到的结果就是:
1.打开页面(localhost:8080)
2.获取到数据
3.页面跳转到 localhost:8080/#/home, 该页面的内容在 App.vue中的标签中显示
4.而homePage中的 router-view 标签中也载入了 homePageMain 的内容
5.内容渲染出来
但是实际上每一次打开页面,或在localhost:8080/#/home 刷新页面的时候,会出现这种情况
所有应该渲染出来的数据都没有渲染出来,都为空白
但是打开vue工具,查看vuex,可以看到数据是获取到的,axios也并没有报错。
如果这个时候我面点开另外一个页面,比如 localhost:8080/#/search 这是另外一个页面
然后我们回到home页面,会发现数据渲染出来了
然后刷新页面,数据又没有渲染出来,这是一个比较恶劣的bug
# 判断问题
通过查看控制台
# 打开 localhost:8080 控制台输出
1.app.vue.created执行了
2.homePage.vue.created执行了
3.homePage.vue.mounted执行了
4.homePageMain.vue.created执行了
5.homePageMain.vue.mounted执行了
6.carseAndComTab.vue.mounted执行了
7.the allUsers is ready
在这里就发现了问题:在后续的代码已经执行的情况之下,axios发送的请求还未得到返回
$store.state.allUsers还未完成数据载入,因此是空数组
渲染出来的页面数据也就为空,而之后数据才进行载入,没有触发更新,不触发响应,因此第一次进入页面时没有数据渲染出来
而点进别的页面,而后退回来,因为已经载入了数据,所以数据正常渲染
# 在 localhost:8080/#/home 页面进行刷新
1.app.vue.created执行了
2.homePage.vue.created执行了
3.homePage.vue.mounted执行了
4.homePageMain.vue.created执行了
5.homePageMain.vue.mounted执行了
6.the allUsers is ready
7.carseAndComTab.vue.mounted执行了
# 问题确定
到这里基本上就可以确定问题的发生原因:第一次打开网页,页面渲染了但是数据还没载入(更新)
进一步判断问题出处: axios.get('...').then(res => {...})
这是一个异步请求。
数据还没发送回来,还没载入,后面的代码就已经开跑了。
# 解决问题
# 思路
既然我们要默认跳转到 /home 页面,那么首先为了保证代码能够执行,我们把路由中的 redirect: '/home' 去掉
通过 this.$router.push({path: '/home'}) 来实现
为了避免数据还未获取到就跳转页面,所以我们需要添加一个判断条件,来判断数据是否已经获取到,然后才跳转页面
那么这个判断-跳转的方法应该添加在哪里?created? mounted? 实际上都不对,因为axios.get...then...是异步操作,数据获取到的时间我们不能确定到,除非我们写一个不断判断的方法,但显然这样子并不可取
我们把这个判断-跳转的方法写在 axios.get...then(res => {这里面}),也就是写在回调函数之中,这样子便可精准的在数据获取到了之后进行判断,然后跳转
在 $store.state 中, 添加一个状态: allUsersReady: false
修改 mutations.getAllUsers ,添加语句 state.allUsersReady = true
在axios.get..then 回调函数中,添加语句
axios.get('/user/allUsers')
.then(res => {
this.$store.commit('getAllUsers', res.data.list)
if (this.$store.state.allUsersReady) {
this.$router.push('/home')
}
})
到这里,我们大体上解决了,打开 localhost:8080 时,数据全部为空的错误,但是接下来还有一个问题为解决
那就是在 /home 页面刷新之后,数据依旧丢失的问题
因为上述判断的是当满足条件之后才跳转到 home,但本身在home页面刷新之后数据依旧是比页面渲染慢的
故技重施,我们再加一个判断,在homePage.vue 的div上,加上 v-if
<div v-if="$store.state.allUsersReady">
<!-- 省略 -->
</div>
这样子,在数据没有载入之前,不会进行渲染
为了界面美观,我们也可以使用element-ui提供的loading组件或其他组件,这里就不加以描述
# 最后代码
// App.vue
//...
created () {
axios.get('/user/allUsers')
.then(res => {
this.$store.commit('getAllusers', res.data.list)
this.toHome()
})
.catch(err => {
console.log(err)
})
}
// ...
methods:{
toHome () {
if (this.$store.state.allUsersReady) {
this.$router.push({path: '/home'})
}
}
}
// 路由 index.js
//...
{
path: '/'
}
<!-- homePage.vue -->
<el-main v-if="$store.state.allPostsReady">
<!-- ... -->
</el-main>