<template>
|
<div class="image-viewer-wrapper">
|
<div class="image-toolbar">
|
<button @click="zoomOut" class="toolbar-btn" :disabled="scale <= 0.5">
|
<span class="icon">−</span>
|
</button>
|
<span class="zoom-info">{{ Math.round(scale * 100) }}%</span>
|
<button @click="zoomIn" class="toolbar-btn" :disabled="scale >= 3">
|
<span class="icon">+</span>
|
</button>
|
<div class="toolbar-divider"></div>
|
<button @click="prevPage" class="toolbar-btn" :disabled="currentPage <= 1">
|
<span class="icon">‹</span>
|
</button>
|
<span class="page-info">{{ currentPage }} / {{ totalPages }}</span>
|
<button @click="nextPage" class="toolbar-btn" :disabled="currentPage >= totalPages">
|
<span class="icon">›</span>
|
</button>
|
</div>
|
<div class="image-content" ref="imageContainer">
|
<img
|
:src="currentImageUrl"
|
:style="{ transform: `scale(${scale})`, transformOrigin: 'top left' }"
|
class="viewer-image"
|
@load="onImageLoad"
|
@error="onImageError"
|
/>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
export default {
|
name: 'ImageViewer',
|
props: {
|
imageUrls: {
|
type: Array,
|
required: true,
|
default: () => []
|
}
|
},
|
data() {
|
return {
|
currentPage: 1,
|
scale: 1.0,
|
loading: false,
|
error: null
|
}
|
},
|
computed: {
|
totalPages() {
|
return this.imageUrls.length
|
},
|
currentImageUrl() {
|
if (this.imageUrls.length === 0) return ''
|
const url = this.imageUrls[this.currentPage - 1]
|
// 添加token
|
const token = typeof window !== 'undefined' && window.localStorage ? window.localStorage.getItem('USERTOKEN') || '' : ''
|
if (url && url.indexOf('token=') === -1) {
|
return url + (url.indexOf('?') > -1 ? '&' : '?') + 'token=' + encodeURIComponent(token)
|
}
|
return url
|
}
|
},
|
methods: {
|
zoomIn() {
|
this.scale = Math.min(this.scale + 0.2, 3)
|
},
|
zoomOut() {
|
this.scale = Math.max(this.scale - 0.2, 0.5)
|
},
|
prevPage() {
|
if (this.currentPage > 1) {
|
this.currentPage--
|
this.scale = 1.0
|
}
|
},
|
nextPage() {
|
if (this.currentPage < this.totalPages) {
|
this.currentPage++
|
this.scale = 1.0
|
}
|
},
|
onImageLoad() {
|
this.loading = false
|
this.error = null
|
},
|
onImageError() {
|
this.loading = false
|
this.error = '图片加载失败'
|
}
|
}
|
}
|
</script>
|
|
<style scoped>
|
.image-viewer-wrapper {
|
width: 100%;
|
height: 80%;
|
background: #f5f5f5;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.image-toolbar {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
padding: 10px;
|
background: #fff;
|
border-bottom: 1px solid #e0e0e0;
|
gap: 10px;
|
}
|
|
.toolbar-btn {
|
width: 36px;
|
height: 36px;
|
border: 1px solid rgb(50, 145, 113);
|
background: linear-gradient(-55deg, rgb(50, 145, 113), rgb(50, 145, 113));
|
border-radius: 4px;
|
cursor: pointer;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
font-size: 18px;
|
color: #fff;
|
font-weight: bold;
|
box-shadow: 0 2px 4px rgba(241, 22, 20, 0.3);
|
transition: all 0.3s ease;
|
}
|
|
.toolbar-btn:disabled {
|
opacity: 0.5;
|
cursor: not-allowed;
|
background: #ccc;
|
border-color: #999;
|
box-shadow: none;
|
}
|
|
.toolbar-btn:not(:disabled):hover {
|
background: linear-gradient(-55deg, rgb(50, 145, 113), rgb(50, 145, 113));
|
box-shadow: 0 2px 8px rgba(241, 22, 20, 0.5);
|
transform: translateY(-1px);
|
}
|
|
.toolbar-btn:not(:disabled):active {
|
transform: translateY(0);
|
box-shadow: 0 1px 3px rgba(241, 22, 20, 0.4);
|
}
|
|
.zoom-info {
|
min-width: 50px;
|
text-align: center;
|
font-size: 14px;
|
color: #666;
|
}
|
|
.toolbar-divider {
|
width: 1px;
|
height: 24px;
|
background: #e0e0e0;
|
margin: 0 5px;
|
}
|
|
.page-info {
|
min-width: 60px;
|
text-align: center;
|
font-size: 14px;
|
color: #666;
|
}
|
|
.image-content {
|
flex: 1;
|
overflow: auto;
|
display: flex;
|
align-items: flex-start;
|
justify-content: center;
|
padding: 20px;
|
}
|
|
.viewer-image {
|
max-width: 100%;
|
height: auto;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
transition: transform 0.2s;
|
}
|
</style>
|