欢迎来到代码驿站!

vue

当前位置:首页 > 网页前端 > vue

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

时间:2022-09-23 10:10:15|栏目: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+Webpack拆分路由文件实现管理

栏    目:vue

下一篇:element滚动条组件el-scrollbar的使用详解

本文标题:利用vue组件实现图片的拖拽和缩放功能

本文地址:http://www.codeinn.net/misctech/214457.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有