- 最近遇到一个需求,在App内嵌的H5页面上,有一个悬浮的客服图标,点击可跳转客服页面。最初这个客服图标采用的是固定定位的方式。现在新的需求是,可以拖拽该图标到屏幕任意位置,防止遮挡页面内容。
- 思考实现的方式就是绑定
touchstart
、touchmove
、touchend
这三个事件(PC端对应的事件分别为mousedown
、mousemove
、mouseup
),动态更新元素的位置,实现元素随手指(鼠标)移动。
- 将逻辑处理封装成一个mixin,方便引用。处理好滑动穿透问题,防止页面随元素移动而滚动。
方法封装
/**
* @name: draggable
* @description: 元素拖拽
*/
const draggableMixin = {
data () {
return {
// 元素位置,用于样式绑定,动态更新位置(:style="{left: `${x}px`, top: `${y}px`}")
elePos: {
x: null,
y: null
},
// 手指(鼠标)触摸点[即拖拽开始的位置]距离拖拽元素左上角的距离
diffOfTarget: {
x: 0,
y: 0
}
}
},
methods: {
dragStartHandler (e) {
let touch = e
if (e.touches) {
touch = e.touches[0]
}
this.diffOfTarget.x = touch.clientX - e.target.offsetLeft
this.diffOfTarget.y = touch.clientY - e.target.offsetTop
// 解决滑动穿透问题
let scrollTop = document.scrollingElement.scrollTop
console.log(scrollTop)
// todo 在项目的全局样式下,需要定义一个modal-open的样式类
/**
* body.modal-open {
* position: fixed;
* width: 100%;
* min-height: 100%;
* }
*/
document.body.classList.add(‘modal-open‘)
document.body.style.top = -scrollTop + ‘px‘
},
draggingHandler (e) {
let touch = e
if (e.touches) {
touch = e.touches[0]
}
// 设置拖拽元素的位置
this.elePos.x = touch.clientX - this.diffOfTarget.x
this.elePos.y = touch.clientY - this.diffOfTarget.y
// 限制元素不能超过屏幕
if (this.elePos.x < 0) {
this.elePos.x = 0
} else if (this.elePos.x > window.screen.width) {
this.elePos.x = window.screen.width - e.target.clientWidth
}
if (this.elePos.y < 0) {
this.elePos.y = 0
} else if (this.elePos.y > window.screen.height) {
this.elePos.y = window.screen.height - e.target.clientHeight
}
},
dragEndHandler (e) {
document.body.classList.remove(‘modal-open‘)
}
}
}
export default draggableMixin
引用
<template>
<div>
<img
src="../assets/img/customer-service.png"
class="customer-service"
:style="{‘left‘: elePos.x + ‘px‘, ‘top‘: elePos.y + ‘px‘ }"
@mousedown="dragStartHandler"
@touchstart.stop="dragStartHandler"
@mousemove="draggingHandler"
@touchmove.stop="draggingHandler"
@mouseup="dragEndHandler"
@touchend.stop="dragEndHandler"
>
</div>
</template>
<script>
import draggableMixin from ‘@/mixins/draggable‘
export default {
mixins: [ draggableMixin ]
}
</script>
<style scoped>
.customer-service {
position: fixed;
left: 10px;
top: 200px;
width: 36px;
height: 36px;
cursor: pointer;
}
</style>
Vue移动端实现元素拖拽