Не нужно внедрять в шаблон логику данных - нужно передавать данные для отображения.
Шаблон должен отображать данные - в его сфере знать КАК отобразить, а не ЧТО отобразить.
Такого быть не должно:
<a v-else :href="'https://vk.com/wall'+wall.owner_id +'_'+ wall.id">
Шаблон становится значительно меньше:
<template>
<div class="walls">
<div class="loading" v-if="loading">Loading...</div>
<div v-if="error" class="error">{{ error }}</div>
<div class="album py-5 bg-light" v-if="walls">
<div class="container">
<div class="row">
<div class="col-md-4" v-for="({ href, id, img, text }, index) in list" :key="index">
<div class="card mb-4 shadow-sm">
<img v-if="img" class="card-img-top" style="height: 225px; width: 100%; display: block;" :src="img">
<div class="card-body">
<a :href="href">
<p class="card-text">{{ text }}</p>
</a>
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">{{ id }}</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
Логику переносим в код компонента:
<script>
import axios from 'axios';
const getUrl = (a, b, URL = 'https://vk.com/wall') => `${URL}${a}_${b}`;
export default {
data: () => ({
loading: false,
walls: null,
error: null,
}),
computed: {
list() {
const { walls } = this;
if (!walls) return [];
return walls.map((wall) => {
const { copy_history } = wall;
const { attachments, id, owner_id, text } = copy_history && copy_history[0] ? copy_history[0] : wall;
const href = getUrl(owner_id, id);
const { photo } = (attachments || []).find(({ type }) => type === 'photo');
const img = photo ? photo.photo_1280 : false;
return { href, img, text, id: wall.id };
};
},
},
created() {
this.fetchData();
},
methods: {
async fetchData() {
this.error = this.walls = null;
this.loading = true;
try {
const { data } = await axios.get('/api/walls');
this.walls = data.items;
} catch (error) {
this.error = error.response.data.message || error.message;
} finally {
this.loading = false;
}
}
}
}
</script>