-
多图切换
- 点击底部缩略图切换显示3张主图
- 高亮当前选中缩略图(蓝色边框)
-
图像操作
- 按钮控制:放大/缩小(50%-500%)、90°旋转、一键还原
- 鼠标拖拽查看放大后的图像局部
- 滚轮缩放支持
-
状态显示
- 实时显示缩放百分比(100%为原始尺寸)
- 拖拽时显示抓取光标反馈
-
自适应布局
- 主图区域固定800x600尺寸
- 图片始终居中并保持比例显示
- 缩略图网格自动换行排列
安装@vueuse/core 注意版本
<template>
<div class="image-viewer" ref="container">
<img :src="currentImageSrc"
ref="image"
class="viewer-image"
:style="imageStyle" />
</div>
<div class="controls">
<button @click="zoomIn">放大 (+)</button>
<button @click="zoomOut">缩小 (-)</button>
<button @click="reset">还原</button>
<button @click="rotate">旋转 (90°)</button>
<span class="zoom-level">缩放:{{ getZoomPercentage }}%</span>
</div>
<div class="thumbnail-container">
<div v-for="(thumb, index) in thumbnails"
:key="index"
class="thumbnail"
:class="{ 'active': currentIndex === index }"
@click="switchImage(index)">
<img :src="thumb" alt="Thumbnail" />
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { useMouse } from '@vueuse/core'
// 图片源列表
const images = [
'https://images.unsplash.com/photo-1670272502246-768d249768ca?w=800', // 主图片1
'https://images.unsplash.com/photo-1563089145-599997674d42?w=800', // 主图片2
'https://images.unsplash.com/photo-1519681393784-d120267933ba?w=800' // 主图片3
]
// 缩略图列表(可以是缩小版本的图片或不同图片)
const thumbnails = [
'https://images.unsplash.com/photo-1670272502246-768d249768ca?w=200', // 缩略图1
'https://images.unsplash.com/photo-1563089145-599997674d42?w=200', // 缩略图2
'https://images.unsplash.com/photo-1519681393784-d120267933ba?w=200' // 缩略图3
]
// 当前图片索引和源
const currentIndex = ref(0)
const currentImageSrc = computed(() => images[currentIndex.value])
// DOM 引用
const container = ref(null)
const image = ref(null)
// 图像状态
const scale = ref(1) // 缩放比例
const rotateAngle = ref(0) // 旋转角度
const position = ref({ x: 0, y: 0 }) // 拖动位置
// 计算图片样式
const imageStyle = computed(() => ({
transform: `translate3d(${position.value.x}px, ${position.value.y}px, 0) scale(${scale.value}) rotate(${rotateAngle.value}deg)`,
transformOrigin: 'center center',
willChange: 'transform'
}))
// 计算缩放百分比(安全检查)
const getZoomPercentage = computed(() => {
const safeScale = Number.isFinite(scale.value) ? scale.value : 1
return Math.round(safeScale * 100)
})
// 拖动状态
let isDragging = false
let previousX = 0
let previousY = 0
// 鼠标事件处理
const handleMouseDown = (event) => {
isDragging = true
previousX = event.clientX
previousY = event.clientY
container.value.style.cursor = 'grabbing'
}
const handleMouseMove = (event) => {
if (isDragging) {
const deltaX = event.clientX - previousX
const deltaY = event.clientY - previousY
position.value.x += deltaX
position.value.y += deltaY
previousX = event.clientX
previousY = event.clientY
}
}
const handleMouseUp = () => {
isDragging = false
container.value.style.cursor = 'grab'
}
// 滚轮事件处理
const handleWheel = (event) => {
event.preventDefault()
const delta = event.deltaY > 0 ? -0.1 : 0.1
scale.value = Math.max(0.5, Math.min(5, (scale.value || 1) + delta))
}
// 控制函数
const zoomIn = () => {
scale.value = Math.min(5, (scale.value || 1) + 0.5)
}
const zoomOut = () => {
scale.value = Math.max(0.5, (scale.value || 1) - 0.5)
}
const reset = () => {
scale.value = 1
rotateAngle.value = 0
position.value = { x: 0, y: 0 }
}
const rotate = () => {
position.value = { x: 0, y: 0 }
rotateAngle.value = (rotateAngle.value + 90) % 360
}
// 切换图片函数
const switchImage = (index) => {
currentIndex.value = index
// 重置变换状态以适应新图片
reset()
}
// 挂载时绑定事件
onMounted(() => {
container.value.addEventListener('mousedown', handleMouseDown)
document.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseup', handleMouseUp)
container.value.addEventListener('wheel', handleWheel, { passive: false })
container.value.style.cursor = 'grab'
})
// 卸载时清理事件
onUnmounted(() => {
container.value.removeEventListener('mousedown', handleMouseDown)
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
container.value.removeEventListener('wheel', handleWheel)
})
</script>
<style scoped>
.image-viewer {
position: relative;
width: 800px;
height: 600px;
border: 1px solid #ddd;
overflow: hidden;
margin: 20px auto;
}
.viewer-image {
position: absolute;
max-width: 100%;
max-height: 100%;
object-fit: contain;
user-select: none;
pointer-events: none;
}
.controls {
margin-top: 10px;
text-align: center;
}
button {
padding: 8px 16px;
margin: 0 5px;
cursor: pointer;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
}
button:hover {
background-color: #0056b3;
}
.zoom-level {
margin-left: 10px;
font-size: 14px;
color: #333;
}
.thumbnail-container {
margin-top: 20px;
text-align: center;
display: flex;
justify-content: center;
gap: 10px;
flex-wrap: wrap;
}
.thumbnail {
width: 100px;
height: 75px;
border: 2px solid #ddd;
cursor: pointer;
overflow: hidden;
}
.thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
}
.thumbnail.active {
border-color: #007bff;
box-shadow: 0 0 5px rgba(0,123,255,0.5);
}
</style>

5756

被折叠的 条评论
为什么被折叠?



