Vue.js对接Marvel API时首次点击角色图片不显示问题求助
问题根本原因
- 异步执行时序问题:详情页
mounted中同时触发getCharacter异步请求和getImage拼接图片地址,首次进入时接口还未返回,preUrl还是初始空值,拼接出来的url无效;接口返回更新preUrl后,url是普通data变量,不会自动响应preUrl的变化,因此图片不加载。后续点击时preUrl已经有上一次请求缓存的值,所以能拼出有效地址。 - Vuex使用不规范:异步请求逻辑写在了mutations中,不符合Vuex mutations只能处理同步逻辑的设计规范,导致无法准确监听异步请求完成时机。
修复方案
第一步:修正Vuex逻辑
把异步请求挪到actions中,mutations仅负责同步修改state:
// vuex 相关代码修正 // 先定义state state: { characters: [], character: null, // 单个角色直接用对象,不用数组 preUrl: '' }, mutations: { SET_CHARACTERS(state, list) { state.characters = list }, SET_CHARACTER(state, char) { state.character = char state.preUrl = `${char.thumbnail.path}/` }, CLEAR_CHARACTER(state) { state.character = null state.preUrl = '' } }, actions: { async getCharacters(context) { try { const res = await fetch(`http://gateway.marvel.com/v1/public/characters?apikey=${public_key}`) const data = await res.json() context.commit('SET_CHARACTERS', data.data.results) } catch(err) { console.log(err) } }, async getCharacter(context, id) { context.commit('CLEAR_CHARACTER') // 先清旧数据,避免旧内容闪烁 try { const res = await fetch(`http://gateway.marvel.com/v1/public/characters/${id}?apikey=${public_key}`) const data = await res.json() context.commit('SET_CHARACTER', data.data.results[0]) // 接口返回的是数组,取第一个元素即可 } catch(error) { console.log(error) } } }
第二步:修正详情页(character.vue)逻辑
把图片地址url改成计算属性,自动响应preUrl的变化,无需手动调用拼接方法:
<template> <div> <div class="flex-container" v-if="character"> <!-- 加判断,等数据加载完再渲染 --> <div class="flex"> <h3>{{character.name}}</h3> <p>{{character.description || '暂无描述'}}</p> </div> <div class="flex2"> <img class="char-img" :src="url" :alt="character.name"> </div> </div> <div v-else>加载中...</div> <!-- 加加载状态 --> </div> </template> <script> import {mapState} from 'vuex' export default { name:'Character', data(){ return { size:'landscape_incredible.jpg', } }, computed: { ...mapState({ character: state => state.character, preUrl: state => state.preUrl }), // url改成计算属性,preUrl变化时自动更新 url() { return this.preUrl ? `${this.preUrl}${this.size}` : '' } }, mounted(){ this.$store.dispatch('getCharacter', this.$route.params.id) }, } </script>
可选优化(角色列表页)
列表页的console.log(this.characters)放在mounted里也会打印空值,因为getCharacters是异步请求,如果你需要打印可以加个watch监听characters变化,或者在actions请求完成后打印。
内容的提问来源于stack exchange,提问作者user3035444
相关产品推荐
相关产品推荐

