程序员的一一贯作风,话不多说直接上代码,可预览图片、视频、音频、文件等,图片预览可丝滑拖拽、缩放、旋转。不喜勿喷!
<template>
<div>
<div ref="container" class="previewArea">
<canvas
ref="canvas"
class="img"
v-if="getFileType(fileList[currentIndex]) == 'img'"
@mousedown="handleMousedown"
></canvas>
<video
:src="fileList[currentIndex]"
v-else-if="getFileType(fileList[currentIndex]) == 'video'"
style="height: 500px"
controls
autoplay
fit="contain"
/>
<div v-else-if="getFileType(fileList[currentIndex]) == 'audio'">
<audio :src="fileList[currentIndex]" controls></audio>
<div>
{{
decodeURI(
fileList[currentIndex].substring(
fileList[currentIndex].lastIndexOf('_') + 1
)
)
}}
</div>
</div>
<div v-else>
<el-icon size="30">
<Document />
</el-icon>
<span style="font-size: 12px; line-height: 15px">{{
decodeURI(
fileList[currentIndex].substring(
fileList[currentIndex].lastIndexOf('_') + 1
)
)
}}</span>
</div>
<div
class="leftIcon"
v-if="fileList.length > 1"
@click="changeCurrent('pre')"
>
<el-icon size="25"><ArrowLeft /></el-icon>
</div>
<div
class="rightIcon"
v-if="fileList.length > 1"
@click="changeCurrent('next')"
>
<el-icon size="25"><ArrowRight /></el-icon>
</div>
</div>
<div class="toolOuter" v-if="getFileType(fileList[currentIndex]) == 'img'">
<el-icon size="25" class="optBtn" @click="handleRotate('left')"
><RefreshRight
/></el-icon>
<el-icon size="25" class="optBtn" @click="handleRotate('rigth')"
><RefreshLeft
/></el-icon>
<el-icon size="25" class="optBtn" @click="zoomScale('in')"
><ZoomOut
/></el-icon>
<div class="optBtn">{{ (zoomRate * 100).toFixed(0) }}%</div>
<el-icon size="25" class="optBtn" @click="zoomScale('out')"
><ZoomIn
/></el-icon>
</div>
</div>
</template>
<script setup>
import getFileType from '../utils/getFileType'
import { defineProps, onMounted, ref } from 'vue'
const props = defineProps({
fileListString: { default: '[]', type: String },
current: { default: 0, type: Number }
})
const currentIndex = ref(props.current)
const fileList = JSON.parse(props.fileListString)
const changeCurrent = flag => {
initRotation = 0
if (flag == 'pre') {
currentIndex.value--
if (currentIndex.value < 0) {
currentIndex.value = fileList.length - 1
}
} else if (flag == 'next') {
currentIndex.value++
if (currentIndex.value > fileList.length - 1) {
currentIndex.value = 0
}
}
image.src = fileList[currentIndex.value]
drawImage()
}
// 缩放
const zoomRate = ref(1)
const zoomScale = flag => {
const zoom = flag == 'out' ? 1.1 : 1 / 1.1
scale *= zoom
if (scale < 0.3) {
scale = 0.3
} else if (scale > 2) {
scale = 2
}
zoomRate.value = scale
drawImage()
}
window.addEventListener('mousewheel', e => {
e.preventDefault()
const delta = e.wheelDelta ? e.wheelDelta : -e.deltaY
const zoom = delta > 0 ? 1.1 : 1 / 1.1
// ctx.scale(zoom, zoom)
scale *= zoom
if (scale < 0.3) {
scale = 0.3
} else if (scale > 2) {
scale = 2
}
zoomRate.value = scale
drawImage()
})
// canvas绘图
// 获取元素
const canvas = ref()
const container = ref()
let ctx,
image,
startDrag,
initRotation = 0
let scale = 1
function loadImageAndInitCanvas (src) {
image = new Image()
image.onload = function () {
canvas.value.width = container.value.offsetWidth * 4
canvas.value.height = container.value.offsetHeight * 4
ctx = canvas.value.getContext('2d')
drawImage()
}
image.src = src
}
// 绘制图片到canvas
function drawImage () {
ctx.clearRect(
0,
0,
container.value.offsetWidth * 4,
container.value.offsetHeight * 4
)
ctx.save()
ctx.translate(canvas.value.width / 2, canvas.value.height / 2)
ctx.scale(scale, scale)
ctx.rotate(initRotation)
ctx.drawImage(image, -image.width / 2, -image.height / 2)
ctx.restore()
}
// 鼠标按下事件处理程序
function handleMousedown (e) {
e.preventDefault()
startDrag = { x: e.clientX, y: e.clientY }
container.value.style.cursor = 'move'
document.addEventListener('mousemove', handleMouseMove, { passive: false })
document.addEventListener('mouseup', handleMouseUp, { passive: false })
}
// 鼠标移动事件处理程序
function handleMouseMove (e) {
e.preventDefault()
const diffX = e.clientX - startDrag.x
const diffY = e.clientY - startDrag.y
ctx.translate(diffX, diffY)
drawImage()
startDrag = { x: e.clientX, y: e.clientY }
}
// 鼠标抬起事件处理程序
function handleMouseUp () {
container.value.style.cursor = 'default'
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
}
// 旋转处理程序
function handleRotate (direction) {
initRotation += direction === 'left' ? Math.PI / 2 : -Math.PI / 2
drawImage()
}
onMounted(() => {
loadImageAndInitCanvas(fileList[currentIndex.value])
})
</script>
<style lang="scss" scoped>
.previewArea {
height: 75vh;
border: 1px solid #ddd;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
position: relative;
.img {
position: absolute;
}
.leftIcon,
.rightIcon {
background-color: rgba($color: #000000, $alpha: 0.3);
color: #fff;
position: absolute;
padding: 10px;
border-radius: 25px;
top: 50%;
transform: translateY(-23px);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
z-index: 10;
}
.leftIcon {
left: 0;
}
.rightIcon {
right: 0;
}
}
.toolOuter {
background-color: rgba($color: #000000, $alpha: 0.3);
color: #fff;
display: flex;
justify-content: center;
align-items: center;
padding: 10px 0;
width: 300px;
margin: auto;
.optBtn {
flex: 0 0 50px;
cursor: pointer;
}
}
</style>