利用vue组件实现图片的拖拽和缩放功能

 更新时间:2022年01月18日 15:39:51   作者:封号斗罗-逆天而行  
这篇文章主要给大家介绍了关于利用vue组件实现图片的拖拽和缩放功能的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

前言

vue实现一个组件其实很简单但是要写出一个好的可复用的组件那就需要多学习和钻研一下,一个好的组件必须有其必不可少的有优点:一是能提高应用开发效率、测试性、复用性等;二是组件应该是高内聚、低耦合的;三是组件应遵循单向数据流的原则。

在实现我的图片的拖拽组件我们的搞清其原理,在这里我使用的是mousedown,mousemove和mouseup来实现拖拽。

如图所示:

方法如下:

1.新建ElementDrag.vue文件内容如下:

<template>
    <div class="drag-outer" 
    ref="dragWrap"
    @mousemove="dragMousemove">
        <div class="drag-inner"
        ref="dragElement" 
        @mousedown="dragMousedown"
        @mouseup.stop="isMousedown = false">
            <slot></slot>
        </div>
    </div>
</template>

2. 定义moveStart用于记录拖拽元素初始位置。定义isMousedown变量来判断鼠标是否按下, 如果isMousedown === true鼠标移动就改变darg-inner位置。

<script>
export default {
    name: 'ElementDrag',
    data() {
        return {
            isMousedown: false, //鼠标是否按下
            moveStart: {x: 0, y: 0}, //拖拽元素初始位置
            translate: {x: 0, y: 0}, //计算拖拽元素在下下x,y方向各移动了多少
            scale: 1, //拖拽元素缩放值
        }
    },
    methods: {
        dragMousedown() {
            this.moveStart.x = event.clientX
            this.moveStart.y = event.clientY
            this.isMousedown = true 
        },
        dragMousemove() {
            if(this.isMousedown) {
                this.translate.x += (event.clientX - this.moveStart.x) / this.scale
                this.translate.y += (event.clientY - this.moveStart.y) / this.scale
                this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
                this.moveStart.x = event.clientX
                this.moveStart.y = event.clientY
            }
        }
    }
}
</script>

3.样式部分我们设置外层drag-outer用flex布局让里面元素快速居中, user-drag: none;禁用图片等元素的可拖拽属性。

<style lang="scss" scoped>
.drag-outer {
    width: 100%;
    height: 100%;
    overflow: hidden;
    display: flex;
    justify-content: center;
    align-items: center;
    .drag-inner {
        transform-origin: center center;
        display: flex;
        justify-content: center;
        align-items: center;
        cursor: move;
        user-select: none;
        >* {
            -webkit-user-drag: none;
            user-drag: none;
        }
    }
}
</style>

4.添加鼠标滚轮事件缩放drag-inner元素, e.wheelDelta为正表示放大,为负缩小,值越大表示滚动越快。通过scale控制拖拽元素缩放。同过对组件传值scaleZoom来控制其缩放最大最小程度值。

...
methods: {
    props: {
        type: Object,
        default(){ 
            return {
                min: 0.5,
                max: 5   
            }
        }
    },
    ...
    handleScroll(e) {
        let speed = e.wheelDelta/120
        if(e.wheelDelta > 0 && this.scale < this.scaleZoom.max) {
            this.scale+=0.04*speed
            this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
        }else if(e.wheelDelta < 0 && this.scale > this.scaleZoom.min){
            this.scale+=0.04*speed
            this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
        }
    }
},
mounted() {
    window.addEventListener('mousewheel',this.handleScroll,false) 
}

5.以上代码已经实现了功能我们预期的功能,但是为了更好的体验,需要进一步优化组件。添加isHover来控制鼠标是否移动到了drag-outer以外,如果isHover为false这时鼠标滚轮滚动不会缩放元素,并且将isMousedown设置为false。再使用插槽slot预览位置。

<template>
    <div class="drag-outer" 
    ref="dragWrap"
    @mouseenter="isHover = true" 
    @mouseleave="isHover = isMousedown = false"
    @mousemove="dragMousemove">
        <div class="drag-inner"
        ref="dragElement" 
        @mousedown="dragMousedown"
        @mouseup.stop="isMousedown = false">
            <slot></slot>
        </div>
    </div>
</template>
....
data() {
    return {
        ...,
        isHover: false,
    }
},
methods: {
    ...
    handleScroll(e) {
        if(this.isHover) {
            let speed = e.wheelDelta/120
            if(e.wheelDelta > 0 && this.scale < this.scaleZoom.max) {
                this.scale+=0.04*speed
                this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
            }else if(e.wheelDelta < 0 && this.scale > this.scaleZoom.min){
                this.scale+=0.04*speed
                this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
            }
        }
    }
}

贴上组件的最终代码:

<template>
    <div class="drag-outer" 
    ref="dragWrap"
    :style="outerOptions"
    @mouseenter="isHover = true" 
    @mouseleave="isHover = isMousedown = false"
    @mousemove="dragMousemove">
        <div class="drag-inner"
        ref="dragElement" 
        :style="innerOptions"
        @mousedown="dragMousedown"
        @mouseup.stop="isMousedown = false">
            <slot></slot>
        </div>
    </div>
</template>

<script>
export default {
    name: 'ElementDrag',
    props: {
        outerOptions: {
            type: Object,
            default () {
                return {
                    background: 'rgba(0,0,0,0.9)'
                }
            }
        },
        innerOptions: {
            type: Object,
            default () {
                return {
                    background: 'rgba(0,0,0,0.1)',
                }
            }
        },
        scaleZoom: {
            type: Object,
            default () {
                return {
                    max: 5, 
                    min: 0.2
                }
            }
        }
    },
    data() {
        return {
            isMousedown: false,
            isHover: false,
            moveStart: {},
            translate: {x: 0, y: 0},
            scale: 1
        }
    },
    methods: {
        handleScroll(e) {
            if(this.isHover) {
                let speed = e.wheelDelta/120
                if(e.wheelDelta > 0 && this.scale < this.scaleZoom.max) {
                    this.scale+=0.04*speed
                    this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
                }else if(e.wheelDelta < 0 && this.scale > this.scaleZoom.min){
                    this.scale+=0.04*speed
                    this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
                }
            }
        },
        dragMousedown() {
            this.moveStart.x = event.clientX
            this.moveStart.y = event.clientY
            this.isMousedown = true 
        },
        dragMousemove() {
            if(this.isMousedown) {
                this.translate.x += (event.clientX - this.moveStart.x) / this.scale
                this.translate.y += (event.clientY - this.moveStart.y) / this.scale
                this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
                this.moveStart.x = event.clientX
                this.moveStart.y = event.clientY
            }
        }
    },
    mounted() {
        window.addEventListener('mousewheel',this.handleScroll,false) 
    }
}
</script>

<style lang="scss" scoped>
.drag-outer {
    width: 100%;
    height: 100%;
    overflow: hidden;
    display: flex;
    justify-content: center;
    align-items: center;
    .drag-inner {
        transform-origin: center center;
        display: flex;
        justify-content: center;
        align-items: center;
        cursor: move;
        user-select: none;
        >* {
            -webkit-user-drag: none;
            user-drag: none;
        }
    }
}
</style>

在home.vue文件使用:点击体验

<template>
  <div class="home">
    <ElementDrag>
        <img src="https://img0.baidu.com/it/u=937276518,3474029246&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=750">
    </ElementDrag>
  </div>
</template>

<script>
import ElementDrag from '@/components/ElementDrag'
export default {
  name: 'Home',
  components: {
    ElementDrag
  }
}
</script>

<style scoped>
.home {
  width: 100vw;
  height: 100vh;
} 
</style>

总结

到此这篇关于利用vue组件实现图片的拖拽和缩放功能的文章就介绍到这了,更多相关vue组件实现图片拖拽缩放内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue中 process.env与process.VUE_CLI_SERVICE详解

    vue中 process.env与process.VUE_CLI_SERVICE详解

    这篇文章主要介绍了vue中process.env与process.VUE_CLI_SERVICE的相关资料,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • vue v-viewer组件使用示例详解(v-viewer轮播图)

    vue v-viewer组件使用示例详解(v-viewer轮播图)

    这篇文章主要介绍了vue v-viewer组件使用示例详解(v-viewer轮播图),本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-02-02
  • Vue3响应式方案及ref reactive的区别详解

    Vue3响应式方案及ref reactive的区别详解

    众所周知ref和reactive都是用来作响应式数据,下面这篇文章主要给大家介绍了关于Vue3响应式方案及ref reactive区别的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • Vue组件之间的通信方式详细讲解

    Vue组件之间的通信方式详细讲解

    对于vue来说,组件之间的消息传递是非常重要的,用vue可以是要组件复用的,而组件实例的作用域是相互独立,这意味着不同组件之间的数据无法互相引用,一般来说,组件之间可以有几种关系,下面是我对组件之间消息传递的常用方式的总结
    2022-08-08
  • Vue Router 中meta 对象示例详解

    Vue Router 中meta 对象示例详解

    本文主要介绍了在VueRouter中,meta对象的使用和配置方式,meta对象可以包含任何你希望附加到路由的自定义信息,这些配置信息可以灵活的满足你的应用需求,使得路由配置更具灵活性和可扩展性
    2024-10-10
  • vue项目引入远程jweixin-1.2.0.js文件并使用详解

    vue项目引入远程jweixin-1.2.0.js文件并使用详解

    这篇文章主要介绍了vue项目引入远程jweixin-1.2.0.js文件并使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-03-03
  • vue框架搭建之axios使用教程

    vue框架搭建之axios使用教程

    本文重点介绍axios如何配合vue搭建项目框架,文章给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-07-07
  • nuxt实现封装axios并且获取token

    nuxt实现封装axios并且获取token

    这篇文章主要介绍了nuxt实现封装axios并且获取token,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • 如何在宝塔面板部署vue项目

    如何在宝塔面板部署vue项目

    这篇文章主要给大家介绍了关于如何在宝塔面板部署vue项目的相关资料,宝塔面板可以通过Nginx来部署Vue项目,并解决跨域问题,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • vue项目引入本地bootstrap不生效问题及解决

    vue项目引入本地bootstrap不生效问题及解决

    这篇文章主要介绍了vue项目引入本地bootstrap不生效问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10

最新评论