首页 > 其他分享 >Vue3实现图片滚轮缩放和拖拽

Vue3实现图片滚轮缩放和拖拽

时间:2023-11-14 09:35:19浏览次数:37  
标签:滚轮 const 缩放 url image height width let Vue3

在项目开发中遇到一个需求:

1:用鼠标滚轮可对图片进行缩放处理

2:点击按钮可对图片进行缩放处理

3:可对图片进行拖拽处理

 

我在开发中通过自己实现与百度查看优秀的铁子进行了两种类型的使用

 

 

<template>
    <div ref="imgWrap" class="wrap" @mousewheel.prevent="rollImg">
        <img :src="url" alt ref="image" @mousedown.prevent="moveImg" />
    </div>
</template>
<script setup>
import { ref } from 'vue'
const url = ref("https://w.wallhaven.cc/full/8o/wallhaven-8oky1j.jpg")

const image = ref(null)
const rollImg = (e) => {
    let transform = image.value.style.transform
    let zoom = transform.indexOf("scale") != -1 ? +transform.split("(")[1].split(")")[0] : 1
    zoom += e.wheelDelta / 1200
    if (zoom > 0.1 && zoom < 2) {
        image.value.style.transform = "scale(" + zoom + ")"
    }
}

const imgWrap = ref(null)
const moveImg = (e) => {
    let wrap = imgWrap.value
    let img = image.value
    let x = e.pageX - img.offsetLeft
    let y = e.pageY - img.offsetTop
    // 添加鼠标移动事件
    wrap.addEventListener('mousemove', move)
    function move(e) {
        img.style.left = e.pageX - x + 'px'
        img.style.top = e.pageY - y + 'px'
    }
    // 添加鼠标抬起事件,鼠标抬起,将事件移除
    img.addEventListener('mouseup', () => {
        wrap.removeEventListener('mousemove', move)
    })
    // 鼠标离开父级元素,把事件移除
    wrap.addEventListener('mouseout', () => {
        wrap.removeEventListener('mousemove', move)
    })
}
</script>

<style lang='less' scoped>
.wrap {
    position: relative;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
img {
    position: absolute;
    cursor: move;
}
</style>

顺便又写了个vue2 的

<template>
    <!-- 舆图库详情页 -->
    <div class="mainPage">
 
        <div class="watchMap">
            <div class="imgBox" ref="maskBox" @mousedown="onmousedownHandle">
                <img :src="imageUrl" alt="" :style="{
                    width: imgW + 'px',
                    height: imgH + 'px',
                    top: top + 'px',
                    left: left + 'px',
                    transform: scale,
                }" />
            </div>
 
            <div class="Tools">
                <div class="Tools-item" @click="imgScaleHandle(0.25)">
                    大
                </div>
                <div class="Tools-item" @click="imgScaleHandle(-0.25)">
                    小
                </div>
                <div class="Tools-item">
                    藏
                </div>
                <div class="Tools-item" @click="
    downloadByBlob(
        'https://img2.baidu.com/it/u=1395980100,2999837177&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=675',
        'name'
    )
                ">
                    下载
                </div>
            </div>
        </div>
 
    </div>
</template>
 
<script>
export default {
 
    data() {
        return {
            imageUrl:
                "https://img2.baidu.com/it/u=1395980100,2999837177&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=675",
 
            imgW: 0,
            imgH: 0,
            deg: 0,
            top: 0,
            left: 0,
            scale: "scale(1)",
            size: 0,
            mousewheelevt: null,
        };
    },
 
    mounted() {
        //初始化图片
        this.initImage();
 
        // 兼容火狐浏览器
        this.mousewheelevt = /Firefox/i.test(navigator.userAgent)
            ? "DOMMouseScroll"
            : "mousewheel";
        // 为空间区域绑定鼠标滚轮事件 =》 处理函数是wheelHandle
        // 如果你监听了window的scroll或者touchmove事件,你应该把passive设置为true,这样滚动就会流畅很多
        this.$refs.maskBox.addEventListener(this.mousewheelevt, this.wheelHandle);
    },
    beforeDestroy() {
        //取消监听
        this.$refs.maskBox.removeEventListener(
            this.mousewheelevt,
            this.wheelHandle
        );
    },
    created() {
        this.handleReset();
    },
    methods: {
        /**
         *
         * 下載圖片
         * **/
 
        downloadByBlob(url, name) {
            let image = new Image();
            image.setAttribute("crossOrigin", "anonymous");
            image.src = url;
            image.onload = () => {
                let canvas = document.createElement("canvas");
                canvas.width = image.width;
                canvas.height = image.height;
                let ctx = canvas.getContext("2d");
                ctx.drawImage(image, 0, 0, image.width, image.height);
                canvas.toBlob((blob) => {
                    let url = URL.createObjectURL(blob);
                    this.download(url, name);
                    // 用完释放URL对象
                    URL.revokeObjectURL(url);
                });
            };
        },
        download(href, name) {
            let eleLink = document.createElement("a");
            eleLink.download = name;
            eleLink.href = href;
            eleLink.click();
            eleLink.remove();
        },
 
        /**
         * 重置
         */
        handleReset() {
            this.imgW = 0;
            this.imgH = 0;
            this.top = 0;
            this.left = 0;
            this.deg = 0;
            this.scale = "scale(1)";
            this.size = 0;
            this.initImage();
        },
        /**
         * 获取图片的url
         * @param {string} url
         */
        getImgSize(url) {
            return new Promise((resolve, reject) => {
                let imgObj = new Image();
                imgObj.src = url;
                imgObj.onload = () => {
                    resolve({
                        width: imgObj.width,
                        height: imgObj.height,
                    });
                };
            });
        },
        /**
         * 初始化图片
         */
        async initImage() {
            if (!this.imageUrl) {
                return;
            }
            let { width, height } = await this.getImgSize(this.imageUrl);
            // 设置原始图片的大小
            let realWidth = width;
            let realHeight = height;
 
            // 获取高宽比例
            const whRatio = realWidth / realHeight;
            const hwRatio = realHeight / realWidth;
 
            //获取盒子的大小
            const boxW = this.$refs.maskBox.clientWidth;
            const boxH = this.$refs.maskBox.clientHeight;
 
            if (realWidth >= realHeight) {
                this.imgH = hwRatio * boxW;
                const nih = this.imgH;
                if (nih > boxH) {
                    this.imgH = boxH;
                    this.imgW = whRatio * boxH;
                } else {
                    this.imgW = boxW;
                }
                this.top = (boxH - this.imgH) / 2;
                this.left = (boxW - this.imgW) / 2;
            } else {
                this.imgW = (boxH / realHeight) * realWidth;
                this.imgH = boxH;
                this.left = (boxW - this.imgW) / 2;
            }
        },
        imgScaleHandle(zoom) {
            this.size += zoom;
            if (this.size < -0.5) {
                this.size = -0.5;
            }
            this.scale = `scale(${1 + this.size}) rotateZ(${this.deg}deg)`;
        },
        /**
         * 鼠标滚动 实现放大缩小
         */
        wheelHandle(e) {
            e.preventDefault();
            const ev = e || window.event; // 兼容性处理 => 火狐浏览器判断滚轮的方向是属性 detail,谷歌和ie浏览器判断滚轮滚动的方向是属性 wheelDelta
            // dir = -dir; // dir > 0 => 表示的滚轮是向上滚动,否则是向下滚动 => 范围 (-120 ~ 120)
            const dir = ev.detail ? ev.detail * -120 : ev.wheelDelta;
            //滚动的数值 / 2000 => 表示滚动的比例,用此比例作为图片缩放的比例
            this.imgScaleHandle(dir / 2000);
        },
        /**
         * 处理图片拖动
         */
        onm ousedownHandle(e) {
            const that = this;
            this.$refs.maskBox.onmousemove = function (el) {
                const ev = el || window.event; // 阻止默认事件
                ev.preventDefault();
                that.left += ev.movementX;
                that.top += ev.movementY;
            };
            this.$refs.maskBox.onmouseup = function () {
                // 鼠标抬起时将操作区域的鼠标按下和抬起事件置为null 并初始化
                that.$refs.maskBox.onmousemove = null;
                that.$refs.maskBox.onmouseup = null;
            };
            if (e.preventDefault) {
                e.preventDefault();
            } else {
                return false;
            }
        },
    },
};
</script>
 
<style lang="scss" scoped>
.world_map {
    width: 1200px;
    margin: 41px auto;
 
    .name {
        width: 95px;
        margin: 0 auto;
        font-size: 22px;
        font-family: "st";
        font-weight: bold;
        color: pink;
        line-height: 30px;
        letter-spacing: 1px;
    }
}
 
.watchMap {
    width: 1200px;
    height: 662px;
    background: pink;
    position: relative;
    // overflow: hidden;
    margin-left: 360px;
 
    .imgBox {
        width: 100%;
        height: 100%;
        overflow: hidden;
        position: relative;
 
        img {
            cursor: move;
            position: absolute;
        }
    }
 
    .Tools {
        width: 43px;
        min-height: 100px;
        position: absolute;
        right: -50px;
        top: 0;
        user-select: none;
 
        .Tools-item {
            width: 100%;
            height: 44px;
            background: pink;
            margin-bottom: 5px;
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: pointer;
 
        }
 
        .Tools-item:hover{
            background-color: red;
            color: #fff;
        }
    }
}
</style>

 

 

写在最后,

     图片的拖拽和缩放动态的给图片赋值宽高和位置

 

标签:滚轮,const,缩放,url,image,height,width,let,Vue3
From: https://www.cnblogs.com/houxianzhou/p/17830906.html

相关文章

  • vue3中的vue-18n的table表格标题不动态变化中英文
    使用computed即可 eg:constcolumns=computed(()=>{returnreactive<any>([{title:proxy.$t('device.pm.table.index'),dataIndex:'index',width:50,slotName:'indexsort',ellipsis:true,......
  • Object.defineProperty(obj,key,val)不可以监听数组变化,需要做特殊处理,所以Vue3.0使用
    关于Vue双向数据绑定说法错误的是()AVue实现双向数据绑定是采用数据劫持和发布者-订阅者模式BObject.defineProperty(obj,key,val)可以监听数组变化,不需要做特殊处理CVue2.0数据劫持是利用ES5的Object.defineProperty(obj,key,val)方法来劫持每个属性的getter和setterD......
  • 图像缩放攻击
    今天在B站上看到一个关于图像缩放攻击的挺有意思的视频。去他的GitHub上复制了源代码来看了看,原理特别简单,核心就是算出缩放点的位置。比如说有一个8个元素的列表[1,1,1,1,1,1,1,1],现在我想把其中的两个元素改成0,而且要求这两个0均匀分布在列表之中。问题就在于选择哪两......
  • vue3搭建
    一、Vue3介绍://创建一个Vue实例constapp=Vue.createApp({data(){return{message:'HelloVue!'}}})app.mount('#app')二、安装Vue3:npminstall-g@vue/cli#或者yarnglobaladd@vue/clivuecreatemy-project三、开始开发:<te......
  • vue2 和 vue3 什么区别
    GitHubCopilot:Vue2和Vue3在许多方面都有所不同,以下是一些主要的区别:CompositionAPI:Vue3引入了CompositionAPI,这是一种新的方式来组织和复用代码。这是与Vue2OptionsAPI相比的一个重大改变。性能:Vue3在性能方面进行了大量优化,包括更小的框架大小,更快......
  • 11 11 vue3代码优化
     使用axios发送异步请求是这种格式,现在异步请求都封装到api中。说法如下:接口调用的js代码一般都会封装到js文件中,并一函数的形式暴露给外部,例如: 这张图片包括了没有参数和有参数的两种情况 然后在组件中的script中调用函数就行,但这样不行,好像跟什么同步异步有关,反正这样......
  • Armoury Crate(奥创中心) 引起的win11鼠标滚轮频繁转圈
    https://answers.microsoft.com/en-us/windows/forum/all/mouse-cursor-constantly-changing-to-busy-after/875f525d-65c3-4116-93e0-673e9ff6ac8a?page=2......
  • PDF统一大小缩放至A4或指定大小
    PDF统一大小缩放至A4或指定大小https://jingyan.baidu.com/article/ed15cb1bb9b95d1be2698163.html如何让pdf中的所有图片宽度一致,高度自适应?去除空白边https://www.zhihu.com/question/449570733?utm_id=0......
  • Vue3(开发h5适配)
    在开发移动端的时候需要适配各种机型,有大的,有小的,我们需要一套代码,在不同的分辨率适应各种机型。因此我们需要设置meta标签<metaname="viewport"content="width=device-width,initial-scale=1.0">移动设备具有各种不同的屏幕尺寸和分辨率,例如智能手机和平板电脑。为了提供更好的......
  • Vue3 路由查询参数更新后,执行更新方法
    import{ref,defineComponent,watch,getCurrentInstance}from"vue";import{useRoute}from'vue-router';exportdefaultdefineComponent({setup(){consttable=ref({key:'spec_id',......