vue3 ts 图像浏览器 图像读取 查看 缩放(以鼠标为中心缩放) 旋转

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>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以通过在`mounted`生命周期中监听鼠标滚轮事件,然后根据鼠标位置和缩放比例计算出视口的缩放中心点和缩放比例,最后使用`transform`样式对视口进行缩放。 以下是一个简单的实现示例: ```html <template> <div class="container" ref="container" @wheel="handleWheel"> <div class="content" ref="content"> <!-- your content here --> </div> </div> </template> <script> export default { mounted() { this.container = this.$refs.container; this.content = this.$refs.content; this.scale = 1; }, methods: { handleWheel(event) { const deltaX = event.deltaX; const deltaY = event.deltaY; const rect = this.container.getBoundingClientRect(); const containerX = event.clientX - rect.left; const containerY = event.clientY - rect.top; const oldScale = this.scale; const newScale = oldScale + deltaY / 100; this.scale = Math.max(1, Math.min(newScale, 5)); const scaleDelta = this.scale - oldScale; const offsetX = containerX * scaleDelta; const offsetY = containerY * scaleDelta; this.content.style.transformOrigin = `${containerX}px ${containerY}px`; this.content.style.transform = `scale(${this.scale}) translate(${offsetX}px, ${offsetY}px)`; }, }, }; </script> <style scoped> .container { width: 100%; height: 100%; overflow: auto; } .content { transform-origin: 0 0; } </style> ``` 解释一下代码: - 在`mounted`生命周期中获取容器和内容的引用,并初始化缩放比例为1。 - 在`handleWheel`方法中获取鼠标滚动的偏移量和容器相对于文档的位置,计算出缩放中心点和缩放比例。 - 根据缩放比例和中心点计算出内容偏移量,并将缩放和偏移应用到内容上。 需要注意的是,这个实现仅支持在容器内部进行缩放,如果需要支持在任意位置进行缩放,需要对容器的滚动条进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值