问题
通过ajax获取mv列表到数组中,然后通过v-for渲染到页面上。此时,想要通过每次渲染时得到mv的id作为参数,传入一个函数中进行新的异步操作,但是遇到了问题。
<div class="card" v-for="(mv,index) in recommendMVs" :key="index">
<div id="mv">
<img :src="mv.picUrl" >
<div id="infoOfMv">
<span >{{mv.name}}</span>
<span>by.{{mv.artistName}}</span>
</div>
</div>
<div id="about">
<img src="../assets/imgs/thumb.png" alt="" class="thumb cardIcon" >
<span>{{mv.likedCount}}</span>
<img src="../assets/imgs/commend.png" alt="" class="commends cardIcon">
<span>{{mv.commentCount}}</span>
</div>
</div>
代码中 recommendMVs 是获取到的mv数组,数组元素是对象。mv对象有id属性,可以通过这个id请求到mv的相关信息,如点赞数,评论数等。
原本想法是把mv.id作为参数,传入一个函数,像这样:
<img src="../assets/imgs/thumb.png" alt="" class="thumb cardIcon" >
<span>{{getInfoOfMv(mv.id)}}</span>
...
getInfoOfMv(id){
return new Promise(function(resolve,reject){
axios.get("https://autumnfish.cn/mv/detail/info?mvid=" + id).then(response =>{
return response
}).then(error => {
})
})
}
然后再这个函数中获取数据,但是因为ajax是异步的,并不能返回想要的数据,还没获取到就返回了
然后想要用Promise,这样可以保证再ajax异步操作结束后才会返回数据,保证能够得到数据。
getInfoOfMv(id){
this.getInfo(id).then(response => {
//这里不能使用return返回结果,只能传给其他量
}).then(function(error){
})
},
getInfo(id){
return new Promise(function(resolve,reject){
axios.get("https://autumnfish.cn/mv/detail/info?mvid=" + id).then(response =>{
resolve(response)
}).then(error => {
})
})
}
但是Promise不能 return 结果,只能把结果传给在data中的其他数据。传给其他值的话,查值表达式中就要写那个数据,这里就不能写成这个函数的形式了,因为使用 {{getInfoOfMv(mv.id)}} 查值表达式的话,只能通过**getInfoOfMv(mv.id)**这个函数返回值来获取数据(计算属性类似)。
可如果把这里绑定给Promise中传给的那个data中的数据,就没法去调用这个函数了,异步就没办法执行。
总结下来,问题有这两个个:
1.只使用函数,会由于异步而取不到值
2.使用Promise的话,就不能使用函数返回值的形式获取数据,只能传给其他的变量,但这样就不能调用这个函数了,也就不能执行异步操作
解决
后来想起来之前写的一个demo中,给使用ajax获取的对象数据,响应式的添加了属性,所以这里也可以使用这种方法。
具体步骤就是:
1.首先使用ajax获取recommendMVs
recommendMVs是 v- for 渲染的基础数据,数组中的每个元素都是一个对象,对象包含了mv.id,可以通过 mv.id 获取想要获取的mv的相关信息,如点赞数,评论数等。
2.获取到之后,对每个数组元素进行遍历,遍历操作就是获取每个对象的mv.id,使用ajax,获取到对应的mv的相关信息
3。将获取到的信息,作为属性,添加到数组 recommendMVs 里对应 mv对象 中
这里注意:因为 recommendMVs 是第一个ajax操作得到的数据,所以这里算是对已有的对象添加响应式的属性。如果使用普通的方法直接添加属性,是不会更新视图的,因此要用Vue.set的方法给对象添加属性,具体可见Vue.js文档
([Vue响应的添加属性(https://cn.vuejs.org/v2/guide/reactivity.html#%E5%AF%B9%E4%BA%8E%E5%AF%B9%E8%B1%A1))
4.在view中,直接使用mv.likedCount (对象.属性名),就和其他原本就在recommendMVs数组里的对象的原有属性一样使用了。
代码:
//组件中
methods: {
async getMVs(){
//获取推荐mv
await this.$store.dispatch('getRecommendMVs')
this.$store.dispatch('getInfoOfMVs')
}
}
//actions中
//第一个ajax,获取recommendMVs
async getRecommendMVs({commit}){
return new Promise((resolve,reject) => {
axios.get(getRecommendMVs).then(function(response){
let recommendMVs = response.data.result
commit(GETRECOMMENDMVS,{recommendMVs})
resolve()
}).then(function(error){
})
})
},
//第二个ajax,对recommendMVs 中每个mv对象,通过mv.id来得到mv对应的相关信息
getInfoOfMVs({commit,state},type){
//对每个得到的mv,获取它的相关信息
state.recommendMVs.forEach( (mv,index) => {
axios.get(getInfoOfMVs + mv.id ).then(function(response){
let likedCount = response.data.likedCount
let commentCount = response.data.commentCount
commit(GETINFOOFMVS,{likedCount,commentCount,index})
}).then(function(error){
})
})
},
//mutations中
[GETRECOMMENDMVS](state,{recommendMVs}){
state.recommendMVs = recommendMVs
},
[GETINFOOFMVS](state,{likedCount,commentCount,index}){
/*
这里如果用以下的方法给对象添加属性,不会更新视图,因为这是对已有的(上个ajax中获取到的)对象添加属性
state.recommendMVs[index].likedCount = likedCount
state.recommendMVs[index].commentCount = commentCount
因此需要用 Vue.set 的方法给对象添加数据
*/
Vue.set(state.recommendMVs[index],'likedCount',likedCount)
Vue.set(state.recommendMVs[index],'commentCount',commentCount)
}
//view中
<div class="card" v-for="(mv,index) in recommendMVs" :key="index">
<div id="mv">
<img :src="mv.picUrl" >
<div id="infoOfMv">
<span >{{mv.name}}</span>
<span>by.{{mv.artistName}}</span>
</div>
</div>
<div id="about">
<img src="../assets/imgs/thumb.png" alt="" class="thumb cardIcon" >
<!-- 这里就可以直接中 对象.属性名 的方式获取数据了,因为已经把数据作为属性传给了对象 -->
<span>{{mv.likedCount}}</span>
<img src="../assets/imgs/commend.png" alt="" class="commends cardIcon">
<span>{{mv.commentCount}}</span>
</div>
</div>