I have a Vue component to show the posts from a database which include images and videos:
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import axios from 'axios';
import { axiosConfig } from '@/config/axios';
const posts = ref<any[]>([]);
const fetchPosts = async () => {
try {
const response = await axios.get('/posts', axiosConfig);
posts.value = response.data.posts.sort((a: any, b: any) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
} catch (error) {
console.error('Failed to fetch posts:', error);
}
};
const isImage = (fileUrl: string): boolean => {
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg'];
const fileExtension = fileUrl.split('.').pop()?.toLowerCase();
return imageExtensions.includes(fileExtension || '');
};
const isVideo = (fileUrl: string): boolean => {
const videoExtensions = ['mp4', 'webm', 'ogg', 'avi', 'mov', 'flv'];
const fileExtension = fileUrl.split('.').pop()?.toLowerCase();
return videoExtensions.includes(fileExtension || '');
};
const mediaItems = ref<HTMLDivElement | null>(null);
const scrollMedia = (direction: number) => {
if (mediaItems.value) {
const scrollAmount = mediaItems.value.scrollLeft + direction * 220;
mediaItems.value.scrollTo({
left: scrollAmount,
behavior: 'smooth',
});
}
};
onMounted(() => {
fetchPosts();
});
</script>
<template>
<div class="post-container">
<div class="post" v-for="post in posts" :key="post._id">
<div class="media-post">
<button class="post-nav-btn" @click="scrollMedia(-1)">❮</button>
<div class="media-post-items" ref="mediaItems">
<div v-for="(file, index) in post.uploaded" :key="index" class="media-post-item-wrapper">
<div class="media-post-item">
<img v-if="isImage(file.media)" :src="file.media" alt="Post media" />
<video v-else-if="isVideo(file.media)" :src="file.media" controls></video>
</div>
</div>
</div>
<button class="post-nav-btn" @click="scrollMedia(1)">❯</button>
</div>
</div>
</div>
</template>
<style scoped>
.post-container {
overflow: auto;
display: flex;
flex-direction: column;
align-items: center;
height: 80vh;
width: 100%;
position: fixed;
top: 0;
left: 0;
margin-top: 80px;
}
.post {
width: 600px;
border: solid 1px white;
padding: 10px;
border-radius: 10px;
margin-bottom: 20px;
}
.media-post {
position: relative;
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 10px;
}
.media-post img, .media-post video {
height: 200px;
border-radius: 10px;
object-fit: contain;
}
.media-post-item {
position: relative;
display: inline-block;
overflow: hidden;
border-radius: 10px;
min-height: 220px;
}
/* some post-nav-btn CSS */
.media-post-items {
display: flex;
overflow-x: auto;
scroll-behavior: smooth;
gap: 10px;
}
</style>
The media files are shown but I cannot use post-nav-btn to horizontally scroll. When I click on the post-nav-btn, in browser console, it says:
Uncaught TypeError: mediaItems.value.scrollTo is not a function
at Proxy.scrollMedia (Post.vue:34:26)
at _createElementVNode.onClick._cache.._cache. (Post.vue:59:54)
at callWithErrorHandling (runtime-core.esm-bundler.js:195:19)
at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:202:17)
at HTMLButtonElement.invoker (runtime-dom.esm-bundler.js:696:5)