【无标题】图片放大,拖拽,鼠标滚轮放大,旋转,多图切换,还原,比例显示

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

  1. 多图切换

    • 点击底部缩略图切换显示3张主图
    • 高亮当前选中缩略图(蓝色边框)
  2. 图像操作

    • 按钮控制:放大/缩小(50%-500%)、90°旋转、一键还原
    • 鼠标拖拽查看放大后的图像局部
    • 滚轮缩放支持
  3. 状态显示

    • 实时显示缩放百分比(100%为原始尺寸)
    • 拖拽时显示抓取光标反馈
  4. 自适应布局

    • 主图区域固定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>

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值