- 最近遇到一個需求,在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"
alt=""
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>