Вот что я бы сделал:
Во-первых, я бы переместил всю логику запросов в VueX и сделал свой компонент максимально простым. Это должно быть достигнуто с помощью этого куска кода:
export default {
props: {
user: Object
},
created () {
if (this.user.avatar) {
this.$store.dispatch('fetchImage', this.user.avatar)
}
}
}
Тогда я бы использовал этот простой шаблон для организации своего магазина. Сначала давайте посмотрим, как должно выглядеть состояние:
{
images: {
'/users/1/avatar': 'data:png:base64,....', // An image that have been loaded
'/users/2/avatar': null // An image that is supposed to be loading
}
}
Как видите, объект images
использует URL-адреса изображений в качестве ключей и данные base64 в качестве значений. Если значение данных равно нулю, это означает, что изображение уже загружается.
Давайте теперь посмотрим, как написать действие для обработки этого:
const actions = {
fetchImage ({state, commit}, url) {
if (typeof state.images[url] !== 'undefined') {
return null
}
commit('setImage', {
url,
payload: null
})
return requests.get(url, { responseType: 'arraybuffer'}).then(response => {
commit('setImage', {
url,
payload: `data:${response.headers['content-type']};base64,${Buffer.from(response.data, 'binary').toString('base64')}`
})
})
}
}
Посмотрите на первое условие. Если изображение не undefined
в магазине, мы просто ничего не делаем. Потому что если изображение не undefined
, это означает, что оно либо null
(загрузка), либо имеет значение и загружено.
Сразу после этого условия мы устанавливаем изображение на null
, чтобы другие компоненты не загружали его.
И в конце мы загружаем содержимое изображения и фиксируем его в состоянии.
Давайте теперь посмотрим на шаблон:
<template>
<router-link to="user" class="anchor-image">
<img v-if="$store.state.images[user.avatar]" :src="$store.state.images[user.avatar]" :alt="user.name" class="image">
<div v-else class="image-default">t</div>
</router-link>
</template>
Чтобы проверить, следует ли отображать изображение, вам просто нужно использовать v-if="$store.state.images[user.avatar]"
. Изображение появится, как только оно будет загружено.
$store.state.images[user.avatar]
будет ложным, даже если изображение loading
(имеет значение null
.
Надеюсь, это поможет!
(Вот полный магазин:)
const store = {
state: {
images: {}
},
mutations: {
setImage (state, image) {
Vue.set(state.images, image.url, image.payload)
}
},
actions: {
fetchImage ({state, commit}, url) {
if (state.images[url] !== undefined) {
return null
}
commit('setImage', {
url,
payload: null
})
return requests.get(url, { responseType: 'arraybuffer'}).then(response => {
commit('setImage', {
url,
payload: `data:${response.headers['content-type']};base64,${Buffer.from(response.data, 'binary').toString('base64')}`
})
})
}
}
}