利用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实现图片预览效果实例(放大、缩小、拖拽)
  • vue图片拖拉转放大缩小组件使用详解
  • vue实现放大缩小拖拽功能
  • 实现vue图片缩放方式-拖拽组件
张贴在2