Vue.js组件scrollTo is not a function错误:媒体无法横向滚动求助
解决Vue组件中媒体横向滚动按钮报错问题
问题原因
报错Uncaught TypeError: mediaItems.value.scrollTo is not a function的核心原因:
- 你将
mediaItems这个ref绑定在了v-for循环生成的.media-post-items元素上,Vue会自动把循环内的ref收集为数组,而非单个DOM元素。因此mediaItems.value是数组,不存在scrollTo方法。 - 原
scrollMedia函数没有区分目标帖子的媒体容器,点击按钮会错误地尝试操作所有帖子的容器,逻辑不符合需求。
解决方案
1. 调整滚动函数逻辑
移除全局的mediaItems ref,修改scrollMedia函数为接收目标DOM元素和滚动方向,直接操作指定容器:
const scrollMedia = (target: HTMLDivElement, direction: number) => { const scrollAmount = target.scrollLeft + direction * 220; target.scrollTo({ left: scrollAmount, behavior: 'smooth', }); };
2. 修改模板中的点击事件
通过$event获取按钮的兄弟元素(即对应的媒体容器),传递给滚动函数:
<button class="post-nav-btn" @click="scrollMedia($event.currentTarget.nextElementSibling as HTMLDivElement, -1)">❮</button> <div class="media-post-items"> <!-- 媒体内容 --> </div> <button class="post-nav-btn" @click="scrollMedia($event.currentTarget.previousElementSibling as HTMLDivElement, 1)">❯</button>
3. 修复CSS布局问题
原.media-post的flex-wrap: wrap会导致按钮和媒体容器换行,调整样式确保布局正确:
.media-post { position: relative; display: flex; gap: 10px; margin-top: 10px; align-items: center; /* 按钮与媒体容器垂直居中 */ } .media-post-items { flex: 1; /* 占据剩余空间 */ display: flex; overflow-x: auto; scroll-behavior: smooth; gap: 10px; padding: 10px 0; }
修改后的完整组件代码
<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 scrollMedia = (target: HTMLDivElement, direction: number) => { const scrollAmount = target.scrollLeft + direction * 220; target.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($event.currentTarget.nextElementSibling as HTMLDivElement, -1)">❮</button> <div class="media-post-items"> <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($event.currentTarget.previousElementSibling as HTMLDivElement, 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; gap: 10px; margin-top: 10px; align-items: center; } .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; } .post-nav-btn { background: rgba(0,0,0,0.5); color: white; border: none; border-radius: 50%; width: 40px; height: 40px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; } .post-nav-btn:hover { background: rgba(0,0,0,0.7); } .media-post-items { flex: 1; display: flex; overflow-x: auto; scroll-behavior: smooth; gap: 10px; padding: 10px 0; } /* 隐藏滚动条(可选) */ .media-post-items::-webkit-scrollbar { display: none; } .media-post-items { -ms-overflow-style: none; scrollbar-width: none; } </style>
内容的提问来源于stack exchange,提问作者Alan
相关产品推荐
相关产品推荐

