<template>
<div class="AspJpeg">
<div class="image-container" @wheel.prevent="handleWheel">
<img ref="pic" draggable="false" :src="OneUrl" class="image"
:style="{ transform: `scale(${scale}) translate(${translateX}px, ${translateY}px)` }"></img>
</div>
<!-- <button @click="zoomIn">Zoom In</button>
<button @click="zoomOut">Zoom Out</button>
<button @click="resetImage">Reset</button>
<div>Current Scale: {{ Math.round(scale * 100) }}%</div> -->
<div class="imageButtonBox">
<div class="imageButtonLeft">
<template v-if="currentIndex == 0">
<el-icon size="20" :color="'#808081'">
<ArrowLeftBold />
</el-icon>
</template>
<template v-else>
<el-icon size="20" :color="'#ffffff'" @click="TheNextOneLeft" style="cursor: pointer">
<ArrowLeftBold />
</el-icon>
</template>
{{ currentIndex + 1 }} / {{ urls.length }}
<template v-if="currentIndex == urls.length - 1">
<el-icon size="20" :color="'#808081'" >
<ArrowRightBold />
</el-icon>
</template>
<template v-else>
<el-icon size="20" :color="'#ffffff'" @click="TheNextOneRight" style="cursor: pointer">
<ArrowRightBold />
</el-icon>
</template>
</div>
<div class="RestorationIcon" @click="resetImage" style="cursor: pointer;">
<el-icon size="20">
<RefreshRight />
</el-icon>
</div>
<div class="imageButtonRight">
<el-icon size="20" @click="zoomIn" style="cursor: pointer;">
<ZoomIn />
</el-icon>
<span style="margin: 0 10px;">{{ Math.round(scale * 100) }}%</span>
<el-icon size="20" @click="zoomOut" style="cursor: pointer;">
<ZoomOut />
</el-icon>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const urls = [{
id: 1,
image: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
}, {
id: 2,
image: 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
}, {
id: 3,
image: 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
}, {
id: 4,
image: 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
}]
const OneUrl = ref()
const scale = ref(1)
const translateX = ref(0)
const translateY = ref(0)
const currentIndex = ref(0)
let isDragging = false
let startX = 0
let startY = 0
const pic = ref(null);
let isDrag = false;
let disX, disY;
onMounted(() => {
OneUrl.value = urls[currentIndex.value].image
pic.value.addEventListener('mousedown', function (e) {
isDrag = true;
this.style.cursor = 'move';
e = e || window.event;
const x = e.clientX;
const y = e.clientY;
disX = x - this.offsetLeft;
disY = y - this.offsetTop;
});
document.addEventListener('mousemove', function (e) {
if (!isDrag) {
return;
}
e = e || window.event;
const x = e.clientX;
const y = e.clientY;
pic.value.style.left = x - disX + 'px';
pic.value.style.top = y - disY + 'px';
});
document.addEventListener('mouseup', function () {
isDrag = false;
pic.value.style.cursor = 'default';
});
})
const handleWheel = (event) => {
const deltaY = event.deltaY
if (deltaY > 0 && scale.value > 0.5) {
scale.value -= 0.1
} else if (deltaY < 0 && scale.value < 3) {
scale.value += 0.1
}
}
const resetImage = () => {
scale.value = 1
translateX.value = 0
translateY.value = 0
pic.value.style.transform = `scale(${scale.value}) translate(${translateX.value}px, ${translateY.value}px)`
pic.value.style.left = '0px';
pic.value.style.top = '0px';
}
const zoomIn = () => {
if (scale.value < 3) {
scale.value += 0.1
}
}
const zoomOut = () => {
if (scale.value > 1) {
scale.value -= 0.1
}
}
/**
* 点击
* ***/
const TheNextOneLeft = () => {
console.log(currentIndex.value, '左点')
currentIndex.value -= 1
OneUrl.value = urls[currentIndex.value].image
}
const TheNextOneRight = () => {
console.log(currentIndex.value, '右点')
currentIndex.value += 1
OneUrl.value = urls[currentIndex.value].image
}
</script>
<style scoped lang="scss">
.AspJpeg {
height: calc(100vh - 133px);
background-color: #eaeef3;
display: flex;
justify-content: center;
align-items: center;
position: relative;
.imageButtonBox {
width: 231px;
height: 34px;
border-radius: 32px;
opacity: 0.7;
background: var(--blue-1, #0E1D31);
position: absolute;
bottom: 8%;
left: 50%;
transform: translateX(-50%);
;
// z-index: 2;
color: #FFF;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
display: flex;
align-items: center;
justify-content: space-around;
.imageButtonLeft {
display: flex;
align-items: center;
}
.imageButtonRight {
display: flex;
align-items: center;
}
}
}
.image-container {
width: 690px;
/* 放大区域宽度 */
height: calc(100vh - 133px);
overflow: hidden;
cursor: grab;
/* 修改鼠标样式为抓取手势 */
}
.image {
margin: 10px;
transition: transform 0.3s ease;
/* 添加过渡效果 */
}
</style>
<template>
<div class="AspJpeg" :style="style">
<div class="image-container" @wheel.prevent="handleWheel" :style="style">
<img ref="pic" draggable="false" :src="OneUrl" class="image"
:style="{ transform: `scale(${scale}) translate(${translateX}px, ${translateY}px)` }" />
</div>
<!-- <button @click="zoomIn">Zoom In</button>
<button @click="zoomOut">Zoom Out</button>
<button @click="resetImage">Reset</button>
<div>Current Scale: {{ Math.round(scale * 100) }}%</div> -->
<div class="imageButtonBox">
<div class="imageButtonLeft">
<template v-if="currentIndex == 0">
<el-icon size="20" :color="'#808081'">
<ArrowLeftBold />
</el-icon>
</template>
<template v-else>
<el-icon size="20" :color="'#ffffff'" @click="TheNextOneLeft" style="cursor: pointer">
<ArrowLeftBold />
</el-icon>
</template>
{{ currentIndex + 1 }} / {{ getImageData.length }}
<template v-if="currentIndex == getImageData.length - 1">
<el-icon size="20" :color="'#808081'">
<ArrowRightBold />
</el-icon>
</template>
<template v-else>
<el-icon size="20" :color="'#ffffff'" @click="TheNextOneRight" style="cursor: pointer">
<ArrowRightBold />
</el-icon>
</template>
</div>
<div class="RestorationIcon" @click="resetImage" style="cursor: pointer;">
<el-icon size="20">
<RefreshRight />
</el-icon>
</div>
<div class="imageButtonRight">
<el-icon size="20" @click="zoomIn" style="cursor: pointer;">
<ZoomIn />
</el-icon>
<span style="margin: 0 10px;">{{ Math.round(scale * 100) }}%</span>
<el-icon size="20" @click="zoomOut" style="cursor: pointer;">
<ZoomOut />
</el-icon>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
// const urls = [
// 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
// 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
// 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
// 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
// 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg',
// ]
// 传递数据
const props = defineProps({
// 数据
getImageData: {
type: Array,
default: () => {
return []
}
},
style: {
type: String,
default: () => {
return ''
}
}
})
const OneUrl = ref()
const scale = ref(1)
const translateX = ref(0)
const translateY = ref(0)
const currentIndex = ref(0)
// let isDragging = false
// let startX = 0
// let startY = 0
const pic = ref(null);
// const isDrag =ref(false);
let isDrag = false;
let disX, disY;
// const disX =ref(0);
// const disY =ref(0)
const getImageData = ref(props.getImageData)
watch(() => props.getImageData, (newValue, oldValue) => {
console.log(newValue)
// 处理getImageData变化的逻辑
getImageData.value = newValue
handData()
})
onMounted(() => {
handData()
})
const handData = () => {
let timer
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
OneUrl.value = getImageData.value[currentIndex.value];
// console.log(OneUrl.value, getImageData.value);
pic.value.addEventListener('mousedown', function (e) {
isDrag = true;
this.style.cursor = 'move';
e = e || window.event;
const x = e.clientX;
const y = e.clientY;
disX = x - this.offsetLeft;
disY = y - this.offsetTop;
});
document.addEventListener('mousemove', function (e) {
if (!isDrag) {
return;
}
e = e || window.event;
const x = e.clientX;
const y = e.clientY;
pic.value.style.left = x - disX + 'px';
pic.value.style.top = y - disY + 'px';
});
document.addEventListener('mouseup', function () {
isDrag = false;
pic.value.style.cursor = 'default';
});
}, 200); // 延迟一秒执行
}
const handleWheel = (event) => {
const deltaY = event.deltaY
if (deltaY > 0 && scale.value > 0.5) {
scale.value -= 0.1
} else if (deltaY < 0 && scale.value < 3) {
scale.value += 0.1
}
}
const resetImage = () => {
scale.value = 1
translateX.value = 0
translateY.value = 0
pic.value.style.transform = `scale(${scale.value}) translate(${translateX.value}px, ${translateY.value}px)`
pic.value.style.left = '0px';
pic.value.style.top = '0px';
}
const zoomIn = () => {
if (scale.value < 3) {
scale.value += 0.1
}
}
const zoomOut = () => {
if (scale.value > 1) {
scale.value -= 0.1
}
}
/**
* 点击
* ***/
const TheNextOneLeft = () => {
console.log(currentIndex.value, '左点')
if (getImageData.value.length > 0) {
currentIndex.value -= 1
OneUrl.value = getImageData.value[currentIndex.value]
} else {
currentIndex.value = 0
}
}
const TheNextOneRight = () => {
console.log(currentIndex.value, '右点')
if (getImageData.value.length > 0) {
currentIndex.value += 1
OneUrl.value = getImageData.value[currentIndex.value]
} else {
currentIndex.value = 0
}
}
</script>
<style scoped lang="scss">
.AspJpeg {
padding: 10px;
height: calc(100vh - 133px);
background-color: #eaeef3;
display: flex;
justify-content: center;
align-items: center;
position: relative;
.imageButtonBox {
width: 231px;
height: 34px;
border-radius: 32px;
opacity: 0.7;
background: #0E1D31;
position: absolute;
bottom: 8%;
left: 50%;
transform: translateX(-50%);
;
// z-index: 2;
color: #FFF;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
display: flex;
align-items: center;
justify-content: space-around;
.imageButtonLeft {
display: flex;
align-items: center;
}
.imageButtonRight {
display: flex;
align-items: center;
}
}
}
.image-container {
max-width: 690px;
/* 放大区域宽度 */
height: calc(100vh - 133px);
overflow: hidden;
cursor: grab;
/* 修改鼠标样式为抓取手势 */
}
.image {
width: 100%;
transition: transform 0.3s ease;
/* 添加过渡效果 */
}
</style>
这段代码是一个Vue组件,用于显示图片并实现缩放、拖动等功能。下面是对代码的解释:
-
<template>
部分包含组件的模板代码,包括一个图片容器.image-container
,内部包含一个图片元素<img>
,以及一些按钮和文字用于控制缩放和切换图片。 -
<script setup>
部分使用了 Vue 3 的 Composition API 的setup
函数来定义组件的逻辑。这部分代码包括:- 引入了
ref
、onMounted
和watch
等函数。 - 定义了一些响应式数据,如图片地址
OneUrl
、缩放比例scale
、水平和垂直偏移量translateX
和translateY
,以及当前图片索引currentIndex
等。 - 监听
props.getImageData
的变化,并在变化时更新图片数据并调用handData
方法。 - 在组件挂载时调用
handData
方法初始化数据。
- 引入了
-
handData
方法用于处理图片拖动功能。它在图片元素上添加了mousedown
、mousemove
和mouseup
事件监听器,实现了图片的拖动效果。 -
其他方法包括
handleWheel
处理滚轮缩放事件,resetImage
重置图片缩放和位置,zoomIn
和zoomOut
控制缩放功能,以及TheNextOneLeft
和TheNextOneRight
控制切换图片功能。 -
<style scoped lang="scss">
部分包含组件的样式,如容器样式.AspJpeg
、按钮样式.imageButtonBox
、图片容器样式.image-container
和图片样式.image
等。