Vue3:基于按钮切换动态图片展示(附Demo)
- 互联网
- 2025-08-28 14:09:02

目录 前言1. Demo2. 升级Demo3. 终极Demo 前言
原先写过类似的知识点:
详细分析el-breadcrumb 面包屑的基本知识(附Demo)详细分析el-card中的基本知识(附Demo)本篇博客将介绍如何通过点击按钮切换不同的图片,并优化交互体验,使页面更流畅、响应更快
主要的知识点:
Vue 3 组件化开发 - 通过 setup 组合式 API 进行数据管理动态绑定 class - 根据当前选中的图片高亮按钮过渡动画 transition - 让图片切换更流畅图片预加载 - 避免切换时的卡顿样式优化 - 让按钮和图片展示更美观 1. Demo最初始的版本Demo:
<template> <div> <!-- 按钮组 --> <div class="button-group"> <button v-for="image in images" :key="image.id" @click="currentImage = image.src"> {{ image.label }} </button> </div> <!-- 动态展示图片 --> <div class="image-container"> <img v-if="currentImage" :src="currentImage" alt="Dynamic Image" /> </div> </div> </template> <script setup> import { ref } from 'vue' // 当前选中的图片 const currentImage = ref(null) // 定义按钮与对应的图片路径(public 目录下的图片) const images = [ { id: 'img1', label: '图片1', src: '/image1.png' }, { id: 'img2', label: '图片2', src: '/image2.png' }, { id: 'img3', label: '图片3', src: '/image3.png' }, { id: 'img4', label: '图片4', src: '/image4.png' } ] </script> <style scoped> .button-group { display: flex; gap: 10px; margin-bottom: 20px; } button { padding: 8px 12px; cursor: pointer; } .image-container { text-align: center; } img { max-width: 100%; height: auto; } </style>截图如下:
2. 升级Demo这一版本有个缺点,就是卡顿,但是他的样式很好看!
图片加载问题:每次点击都会重新加载图片,导致延迟样式导致的渲染卡顿:box-shadow、border 变化可能导致重绘事件未优化:Vue 响应式 ref 更新时,可能导致不必要的 DOM 计算更改相关样式以及按钮:
<template> <div class="container"> <!-- 按钮组 --> <div class="button-group"> <button v-for="image in images" :key="image.id" @click="currentImage = image.src" class="image-button"> <img :src="image.src" alt="Preview" class="button-thumbnail" /> <span>{{ image.label }}</span> </button> </div> <!-- 动态展示图片 --> <div class="image-container"> <img v-if="currentImage" :src="currentImage" alt="Dynamic Image" class="main-image" /> </div> </div> </template> <script setup> import { ref } from 'vue' // 当前选中的图片 const currentImage = ref(null) // 定义按钮与对应的图片路径(public 目录下的图片) const images = [ { id: 'img1', label: '图片1', src: '/favicon.ico' }, { id: 'img2', label: '图片2', src: '/image2.png' }, { id: 'img3', label: '图片3', src: '/image3.png' }, { id: 'img4', label: '图片4', src: '/image4.png' }, { id: 'img5', label: '图片5', src: '/deepSeaField.png' }, { id: 'img6', label: '图片6', src: '/image2.png' }, { id: 'img7', label: '图片7', src: '/image3.png' }, { id: 'img8', label: '图片8', src: '/image4.png' } ] </script> <style scoped> /* 整体容器 */ .container { max-width: 800px; margin: 0 auto; text-align: center; } /* 按钮组:使用网格布局 */ .button-group { display: grid; grid-template-columns: repeat(4, 1fr); /* 4 列布局 */ gap: 15px; margin-bottom: 20px; } /* 按钮样式 */ .image-button { display: flex; flex-direction: column; align-items: center; justify-content: center; background: white; border: 2px solid #ddd; border-radius: 12px; padding: 10px; cursor: pointer; transition: all 0.3s ease-in-out; box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1); } .image-button:hover { background: #f0f0f0; transform: scale(1.05); } /* 按钮里的小缩略图 */ .button-thumbnail { width: 50px; height: 50px; border-radius: 8px; object-fit: cover; margin-bottom: 5px; } /* 主要图片 */ .image-container { margin-top: 20px; } .main-image { max-width: 100%; height: auto; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } </style>截图如下:
后续继续整改优化:
<template> <div class="container"> <!-- 按钮组 --> <div class="button-group"> <button v-for="image in images" :key="image.id" @click="currentImage = image.src" class="image-button"> <img :src="image.src" alt="Preview" class="button-thumbnail" /> <span>{{ image.label }}</span> </button> </div> <!-- 动态展示图片 --> <div class="image-container"> <img v-if="currentImage" :src="currentImage" alt="Dynamic Image" class="main-image" /> </div> </div> </template> <script setup> import { ref } from 'vue' // 当前选中的图片 const currentImage = ref(null) // 定义按钮与对应的图片路径(public 目录下的图片) const images = [ { id: 'img1', label: '图片1', src: '/favicon.ico' }, { id: 'img2', label: '图片2', src: '/image2.png' }, { id: 'img3', label: '图片3', src: '/image3.png' }, { id: 'img4', label: '图片4', src: '/image4.png' }, { id: 'img5', label: '图片5', src: '/deepSeaField.png' }, { id: 'img6', label: '图片6', src: '/image2.png' }, { id: 'img7', label: '图片7', src: '/image3.png' }, { id: 'img8', label: '图片8', src: '/image4.png' } ] </script> <style scoped> /* 整体容器 */ .container { max-width: 1000px; margin: 0 auto; text-align: center; } /* 按钮组:一行排列 */ .button-group { display: flex; justify-content: space-around; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; /* 保证小屏设备时自动换行 */ } /* 按钮样式 */ .image-button { display: flex; flex-direction: column; align-items: center; justify-content: center; background: white; border: 2px solid #ddd; border-radius: 12px; padding: 10px; cursor: pointer; transition: all 0.3s ease-in-out; box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1); width: 100px; /* 固定宽度 */ height: 120px; /* 固定高度 */ } .image-button:hover { background: #f0f0f0; transform: scale(1.05); } /* 按钮里的小缩略图 */ .button-thumbnail { width: 50px; height: 50px; border-radius: 8px; object-fit: cover; margin-bottom: 5px; } /* 主要图片 */ .image-container { margin-top: 20px; display: flex; justify-content: center; align-items: center; height: 600px; /* 固定高度,居中展示大图 */ border: 2px solid #ddd; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } .main-image { max-width: 100%; max-height: 100%; /* 确保图片不会超出容器 */ object-fit: contain; /* 保持图片比例 */ } </style>截图如下:
3. 终极Demo后续发现会很卡顿
优化点
去除黑色边框: 由于 <button> 在不同浏览器默认会有 outline 选中效果,添加 outline: none 解决 通过 border: none 避免额外边框影响
流畅过渡动画: 按钮缩略图 采用 background-image,提高图片加载速度 主图片切换 采用 Vue Transition 并优化 opacity 过渡,使切换更顺畅
减少卡顿: 预加载所有图片,防止首次切换时加载延迟 优化 changeImage 逻辑,避免重复更新 currentImage
<template> <div class="container"> <!-- 按钮组 --> <div class="button-group"> <button v-for="image in images" :key="image.id" @click="changeImage(image.src)" class="image-button" :class="{ active: currentImage === image.src }" > <div class="button-thumbnail" :style="{ backgroundImage: `url(${image.src})` }"></div> <span>{{ image.label }}</span> </button> </div> <!-- 动态展示图片 --> <div class="image-container"> <transition name="fade" mode="out-in"> <img v-if="currentImage" :src="currentImage" alt="Dynamic Image" class="main-image" /> </transition> </div> </div> </template> <script setup> import { ref, onMounted } from 'vue' // 定义按钮与对应的图片路径 const images = [ { id: 'img1', label: '未来制造', src: '/futureManufacturing.png' }, { id: 'img2', label: '未来材料', src: '/futureMaterials.png' }, { id: 'img3', label: '未来信息', src: '/futureInformation.png' }, { id: 'img4', label: '未来能源', src: '/futureEnergy.png' }, { id: 'img5', label: '未来医疗', src: '/futureMedical.png' }, { id: 'img6', label: '人工智能', src: '/artificialIntelligence.png' }, { id: 'img7', label: '数字经济', src: '/digitalEconomy.png' }, { id: 'img8', label: '低空经济', src: '/lowAltitudeEconomy.png' }, { id: 'img9', label: '深海领域', src: '/deepSeaField.png' } ] // 默认选中第一张图片 const currentImage = ref(images[0].src) // 切换图片 const changeImage = (src) => { if (currentImage.value !== src) { currentImage.value = src } } // 预加载图片,减少切换时的卡顿 const preloadImages = () => { images.forEach(image => { const img = new Image() img.src = image.src }) } onMounted(preloadImages) </script> <style scoped> /* 整体容器 */ .container { max-width: 1200px; margin: 0 auto; text-align: center; } /* 按钮组 */ .button-group { display: flex; justify-content: center; gap: 10px; flex-wrap: nowrap; overflow-x: auto; padding: 10px 0; scrollbar-width: none; /* 隐藏滚动条 */ } /* 按钮样式 */ .image-button { display: flex; flex-direction: column; align-items: center; justify-content: center; background: white; border: none; border-radius: 10px; padding: 5px; cursor: pointer; transition: transform 0.2s ease, background 0.2s ease; width: 90px; height: 110px; outline: none; /* 去除点击时的黑框 */ } .image-button:hover { transform: scale(1.05); } /* 选中状态 */ .image-button.active { background: #e3f2fd; box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); } /* 按钮里的小缩略图 */ .button-thumbnail { width: 50px; height: 50px; border-radius: 8px; background-size: cover; background-position: center; margin-bottom: 5px; } /* 主要图片 */ .image-container { will-change: transform, opacity; margin-top: 10px; display: flex; justify-content: center; align-items: center; height: 600px; border-radius: 10px; width: 100%; /* 增加宽度 */ max-width: 1200px; /* 限制最大宽度,防止过大 */ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); overflow: hidden; } .main-image { max-width: 100%; max-height: 100%; object-fit: contain; } /* 过渡动画 */ .fade-enter-active, .fade-leave-active { transition: opacity 0.3s ease-in-out; } .fade-enter, .fade-leave-to { opacity: 0; } </style>Vue3:基于按钮切换动态图片展示(附Demo)由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Vue3:基于按钮切换动态图片展示(附Demo)”