Vue@拖拽组件

2,491 阅读2分钟

概述

最近开发的项目中有一个分享的悬浮按钮,这个按钮遮挡了页面信息,产品经理跑过来问我,是否可以把这个按钮做成可以拖拽的,研究了一下轻松实现了这个功能,这里分享给大家。这个项目是基于vue的公众号网页,所以是通过vue来实现的,给大家一个参考。先来看一看效果:

分析

1. 技术点

  • 插槽
  • 固定定位
  • 组件封装
  • touchemove & mousemove 事件

2. 实现思路

  • 首先封装drag-view组件,组件本身只处理拖拽逻辑,组件内容通过插槽由父组件传入。
  • 将drag-view设置为固定定位,然后在move事件中计算出lefttop赋值给drag-view即可。

3. 处理计算

topleft 值的计算比较简单,我们只需要获取到触摸点的x、y坐标减去容器宽度、高度的一半即可,所以得出以下公式:

top   = clientY - elHeight / 2;
left  = clientX - elWidth  / 2;

代码实现

1. 组件部分

<template>
    <div
        class="drag__wrapper"
        ref="dragRef"
        :style="{top:pos.y+'px', left:pos.x+'px'}"
        @mousemove="onTouchMove"
        @touchmove.stop="onTouchMove"
    >
        <slot />
    </div>
</template>

<script>
export default {
    props: {
        position: {
            type: Object,
            default: () => ({
                x: 300,
                y: 500,
            }),
        },
    },
    data() {
        return {
            flags: false,
            pos: {
                x: 0,
                y: 0,
            },
        };
    },
    mounted() {
        // 设置默认值
        this.pos = { ...this.$props.position };
        // 获取容器元素的尺寸信息
        const rect = this.$refs.dragRef.getBoundingClientRect();
        // 获取容器元素尺寸的一半便于后面计算使用
        this.wrapperHalfWidth = rect.width / 2;
        this.wrapperHalfHeight = rect.height / 2;
        // 获取屏幕的尺寸信息
        const clientWidth =
            document.body.clientWidth || document.documentElement.clientWidth;
        const clientHeight =
            document.body.clientHeight || document.documentElement.clientHeight;
        // 获取拖拽元素在屏幕内可拖拽的边界值
        this.maxX = clientWidth - rect.width;
        this.maxY = clientHeight - rect.height;
    },
    methods: {
        onTouchMove(event) {
            // 获取触点,兼容PC和移动端
            let touch;
            if (event.touches) {
                touch = event.touches[0];
            } else {
                touch = event;
            }
            // 定位滑块的位置
            this.pos.x = touch.clientX - this.wrapperHalfWidth;
            this.pos.y = touch.clientY - this.wrapperHalfHeight;
            // 处理边界
            if (this.pos.x < 0) {
                this.pos.x = 0;
            } else if (this.pos.x > this.maxX) {
                this.pos.x = this.maxX;
            }
            if (this.pos.y < 0) {
                this.pos.y = 0;
            } else if (this.pos.y > this.maxY) {
                this.pos.y = this.maxY;
            }
            // 阻止页面的滑动默认事件
            event.preventDefault();
        },
    },
};
</script>

<style>
.drag__wrapper {
    position: fixed;
}
</style>

2. 调用

<template>
    <div class="page test bg-light">
        <p class="tips">{{tips}}</p>
        <drag-view :position="{x: 300, y : 500}">
            <div class="box" @click="onTap">客服</div>
        </drag-view>
    </div>
</template>

<script>
import DragView from "../../components/DragView/DragView.vue";
export default {
    data() {
        return {
            tips: "",
        };
    },
    methods: {
        onTap() {
            this.tips = "点击客服按钮";
        },
    },
    components: {
        DragView,
    },
};
</script>

<style scoped="scoped" lang="less">
.tips {
    text-align: center;
    margin: 50px 0;
    color: cornflowerblue;
    font-size: 22px;
}
.box {
    width: 50px;
    height: 50px;
    background: cornflowerblue;
    border-radius: 50%;
    text-align: center;
    line-height: 50px;
    color: #ffffff;
    font-size: 16px;
}
</style>

提示:

  1. 调用drag-view组件时通过position属性来设置拖拽按钮的初始位置。
  2. 拖拽按钮点击事件直接在父组件定义即可。

结尾

好了,各位小伙伴,今天的分享就到这里啦,喜欢我文章朋友可以点一波关注,谢谢啦。你的关注,是我继续努力下去的动力。

关注公众号,了解更多干货