imageBrowser.vue
<template>
<div ref="content_obj" class="content"
:style="{ display: !show ? 'none' : '', width: viewPortWidth + 'px', height: viewPortHeight + 'px' }">
<svg t="1690442930805" class="icon_Close" @click="onClose" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="9622" width="40" height="40">
<path
d="M590.305882 512l234.917647-240.941176 12.047059-12.047059-72.282353-72.282353-252.988235 252.988235-252.988235-252.988235-72.282353 72.282353 252.988235 252.988235-252.988235 252.988235 72.282353 72.282353 252.988235-246.964706 240.941176 234.917647 12.047059 12.047059 72.282353-72.282353z"
fill="#ffffff" p-id="9623">
</path>
</svg>
<img ref="image_obj" class="image"
:style="{ transform: 'rotate(' + angle + 'deg)', position: 'relative', left: imageRect.x + 'px', top: imageRect.y + 'px' }"
:width="imageRect.width" :height="imageRect.height" :src="imagePath" />
<div class="foot-bar">
<svg t="1690444392745" class="icon_R90" @click="onRotateRight" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="16659" width="200" height="200">
<path
d="M121.6 502.4c32 0 57.6 25.6 57.6 60.8 0 188.8 147.2 342.4 329.6 342.4 182.4 0 329.6-153.6 329.6-342.4 0-188.8-147.2-342.4-329.6-342.4V320L278.4 160 512 0v99.2c246.4 0 448 208 448 460.8S758.4 1024 512 1024 64 816 64 563.2c0-35.2 25.6-60.8 57.6-60.8"
p-id="16660" fill="#ffffff"></path>
</svg>
<svg t="1690444363676" class="icon_L90" @click="onRotateLeft" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="16456" width="200" height="200">
<path
d="M902.4 502.4c-32 0-57.6 25.6-57.6 60.8 0 188.8-147.2 342.4-329.6 342.4-182.4 0-329.6-153.6-329.6-342.4 0-188.8 147.2-342.4 329.6-342.4V320l233.6-160L512 0v99.2C265.6 99.2 64 307.2 64 563.2S265.6 1024 512 1024s448-208 448-460.8c0-35.2-25.6-60.8-57.6-60.8"
p-id="16457" fill="#ffffff"></path>
</svg>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { getCurrentInstance } from 'vue';
import { nextTick } from 'vue';
import { watch } from 'vue';
import { onMounted } from 'vue';
import { onBeforeUnmount } from 'vue';
const props = defineProps({
src:String
})
const instance = getCurrentInstance()
const content_obj = ref()
const image_obj = ref()
const imageRect = ref({ x: 0, y: 0, width: 0, height: 0 })
let angle = ref(0)
let show = ref(false) //显示当前图像查看层
let imagePath = ref(props.src)
let mousedownPos = { x: 0, y: 0 } //记录鼠标被拖动位置
let canMove=false
let image_zoom = 1.0
let viewPortWidth = ref(window.innerWidth || document.documentElement.clientWidth
|| document.body.clientWidth)
let viewPortHeight = ref(window.innerHeight || document.documentElement.clientHeight
|| document.body.clientHeight)
let imageWidth = 0
let imageHeight =0
watch(
() => props.src,
(src) => {
nextTick(() => {
openImage(String(src)).then(ret=>{
imagePath.value=String(ret)
show.value = true
imageRect.value = { x: 0, y: 0, width:imageWidth , height:imageHeight }
imageFullView()
})
})
}
)
onMounted(() => {
nextTick(() => {
content_obj.value = instance?.refs.content_obj
image_obj.value = instance?.refs.image_obj
content_obj.value.addEventListener('mousewheel', onClientMouseWheel)
content_obj.value.addEventListener('mousedown', onClientMouseDown)
content_obj.value.addEventListener('mouseup', onClientMouseUp)
content_obj.value.addEventListener('mousemove', onClientMouseMove)
content_obj.value.addEventListener('dblclick', onClientMouseDbClick)
window.addEventListener('resize', onResize)
imageFullView()
})
})
onBeforeUnmount(()=>{
if(content_obj.value){
content_obj.value.removeEventListener('mousewheel', onClientMouseWheel)
content_obj.value.removeEventListener('mousedown', onClientMouseDown)
content_obj.value.removeEventListener('mouseup', onClientMouseUp)
content_obj.value.removeEventListener('mousemove', onClientMouseMove)
content_obj.value.removeEventListener('dblclick', onClientMouseDbClick)
}
window.removeEventListener('resize', onResize)
})
function openImage(src: string) {
return new Promise((resolve) => {
nextTick(() => {
var image = new Image()
image.src = src
image.onload = function () {
imageWidth = image.width
imageHeight = image.height
resolve(src)
}
})
});
}
function onClose() {
show.value = false
}
function onRotateRight() {
angle.value = angle.value === -360 ? 0 : angle.value
angle.value += -90
}
function onRotateLeft() {
angle.value = angle.value === 360 ? 0 : angle.value
angle.value += 90
}
function onResize() {
viewPortWidth.value = window.innerWidth || document.documentElement.clientWidth
|| document.body.clientWidth
viewPortHeight.value = window.innerHeight || document.documentElement.clientHeight
|| document.body.clientHeight
nextTick(() => {
imageFullView()
})
}
function imageFullView() {
nextTick(() => {
let _vW = content_obj.value.clientWidth
let _vH = content_obj.value.clientHeight
let _sW = imageWidth
let _sH = imageHeight
if (_sW > _vW) {
//_sW 为准
imageRect.value.width = _vW
imageRect.value.height = _vW / _sW * _sH
} else if (_sH > _vH) {
imageRect.value.width = _vH / _sH * _sW
imageRect.value.height = _vH
} else {
imageRect.value.width = _sW
imageRect.value.height = _sH
}
//置于视图中心
imageRect.value.x = (_vW - imageRect.value.width) / 2.0
imageRect.value.y = (_vH - imageRect.value.height) / 2.0
})
}
function onClientMouseWheel(e: any) {
if(mouseOnClient(e)){
if (e.deltaY < 0) {
image_zoom = 1.1
} else {
image_zoom = 1 / 1.1
}
// 限制缩放大小
if (imageRect.value.width > 100 || e.deltaY < 0) {
//鼠标相对图像的位置
let _pos = { x: e.x - content_obj.value.offsetLeft - imageRect.value.x, y: e.y - content_obj.value.offsetTop - imageRect.value.y }
// 移动图像位置
imageRect.value.x += _pos.x - _pos.x * image_zoom //缩放前和缩放后的距离差x
imageRect.value.y += _pos.y - _pos.y * image_zoom //缩放前和缩放后的距离差y
// 修改图像宽高
imageRect.value.width = imageRect.value.width * image_zoom //缩放后的图像宽
imageRect.value.height = imageRect.value.height * image_zoom //缩放后的图像高
}
}
e.preventDefault();
}
function onClientMouseDown(e: any) {
if(mouseOnClient(e)){
mousedownPos.x = e.x;
mousedownPos.y = e.y;
canMove=true
}else{
canMove=false
}
e.preventDefault();
}
function onClientMouseUp(e: any) {
canMove=false
e.preventDefault();
}
function onClientMouseMove(e: any) {
if (e.buttons === 1 && canMove) {
let _diffPos = { x: mousedownPos.x - e.x, y: mousedownPos.y - e.y }
imageRect.value.x -= _diffPos.x
imageRect.value.y -= _diffPos.y
mousedownPos.x = e.x;
mousedownPos.y = e.y;
}
e.preventDefault();
}
function onClientMouseDbClick(e: any) {
if(mouseOnClient(e)){
imageFullView()
}
e.preventDefault();
}
function mouseOnClient(e:any):boolean{
if(e.target===image_obj.value){
return true
}
return false
}
</script>
<style lang="scss" scoped>
.content {
background-color: #0000007f;
position: absolute;
left: 0px;
top: 0px;
z-index: 9998;
cursor: default;
overflow: hidden;
backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px);
}
.icon_Close {
position: absolute;
right: 20px;
top: 20px;
z-index: 99999;
width: 50px;
height: 50px;
background-color: rgba(120, 120, 120, 0.5);
border-radius: 50%;
padding: 10px;
}
.foot-bar {
position: absolute;
left: 50%;
margin-left: -100px;
bottom: 50px;
width: 200px;
height: 50px;
background-color: rgba(120, 120, 120, 0.5);
border-radius: 50px;
}
.icon_R90 {
position: absolute;
left: 20%;
z-index: 99999;
width: 50px;
height: 50px;
border-radius: 50%;
padding: 10px;
}
.icon_L90 {
position: absolute;
right: 20%;
z-index: 99999;
width: 50px;
height: 50px;
border-radius: 50%;
padding: 10px;
}
</style>
index.vue
<template>
<div>
<el-button color="#626aef" @click="onOpenFile">{{ btn_FileOpen }}
<input ref="openFileDialog_obj" type="file" accept="image/*" style="display: none;"/>
</el-button>
<imageBrowser :src="imagePath"></imageBrowser>
</div>
</template>
<script lang="ts" setup>
import {ref,nextTick,getCurrentInstance} from "vue"
import imageBrowser from '@/components/imageBrowser.vue'
let btn_FileOpen=ref('打开文件')
let imagePath=ref()
const openFileDialog_obj = ref()
const instance = getCurrentInstance()
nextTick(()=>{
openFileDialog_obj.value=instance?.refs.openFileDialog_obj
})
function onOpenFile(){
if (!openFileDialog_obj.value) {
nextTick(() => {
openFileDialog_obj.value = instance?.refs.openFileDialog_obj
})
}
openFileDialog_obj.value.click()
openFileDialog_obj.value.oninput=(value:any)=>{
let path= URL.createObjectURL(value.target.files[0])
imagePath.value=path
value.target.value=''
}
}
</script>