一、实现效果
二、实现代码
主要通过原生的 mousedown
和 mouseup
以及mouseleave
事件实现
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport"
content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, width=device-width" />
<title>拖动效果</title>
<!-- 引入element样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入element组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 引入vue -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script>
<style type="text/css">
#call_state_marked{
position: fixed;
top: 50px;
left: 100px;
z-index: 9;
color: #f00;
background: #fff;
font-size: 16px;
width: 60px;
height: 60px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
box-shadow: -3px 0px 6px 0px #a9a9a980, 3px 0px 6px 0px #a9a9a980;
border-radius: 4px;
}
#call_state_marked span:nth-child(1) {
font-size: 20px;
font-weight: 600;
}
</style>
</head>
<body>
<div id="content">
<div id="call_state_marked" @mousedown="handleMouseDown" @mouseup="handleMouseUp">
<span class="el-icon-phone"></span>
<span>挂断</span>
</div>
</div>
<script>
var vue = new Vue({
el: '#content',
data: {
},
mounted() {
// 监听页面的mouseleave事件,当鼠标移出浏览器页面可用区域 并 松开按键时,停止拖动
document.addEventListener("mouseleave", (e) => {
document.onmousemove = document.onmouseup = null;
});
},
methods: {
// 拖动效果
handleMouseDown(e) {
let box = document.getElementById('call_state_marked');
// e.pageX, e.pageY 是鼠标在页面上的坐标
// box.offsetLeft, box.offsetTop 是元素相对于页面左上角的偏移位置
// disx, disy 便是鼠标相对于元素左上角的偏移位置
let disx = e.pageX - box.offsetLeft;
let disy = e.pageY - box.offsetTop;
// document.documentElement.clientWidth: 浏览器页面可用宽度
// document.documentElement.clientHeight: 浏览器页面可用高度
document.onmousemove = function (e) { // 鼠标移动的时候计算元素的位置
let x, y;
// e.pageX - disx 鼠标在页面上的位置 - 鼠标在元素中的偏移位置 得到的是元素相对于页面左上角的偏移位置
if ((e.pageX - disx) > 0) { // 元素相对于页面左上角的偏移位置 大于0时
if ((e.pageX - disx) > document.documentElement.clientWidth - 60) { // 元素相对于页面左上角的偏移位置 移出到页面以外(右侧)
x = document.documentElement.clientWidth - 60; // 60是元素自身的宽高
} else {
x = e.pageX - disx;
}
} else { // 元素移到到页面以外(左侧)
x = 0;
}
if ((e.pageY - disy) > 0) {
if ((e.pageY - disy) > document.documentElement.clientHeight - 60) { // 元素移动到页面以外(底部)
y = document.documentElement.clientHeight - 60;
} else {
y = e.pageY - disy;
}
} else { // 元素移动到页面以外(顶部)
y = 0;
}
box.style.left = x + 'px';
box.style.top = y + 'px';
}
},
// 释放鼠标按钮,将事件清空,否则始终会跟着鼠标移动
handleMouseUp() {
document.onmousemove = document.onmouseup = null;
},
},
});
</script>
</body>
</html>
功能封装
javascript
//拖拽
function dragMove() {
const playerDOM = document.querySelector(`div[id='screen-Box']`)
playerDOM.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
// const sty = playerDOM.currentStyle || window.getComputedStyle(playerDOM, null)
playerDOM.onmousedown = (e) => {
// const defaultTop = Number(document.defaultView.getComputedStyle(playerDOM, null).marginTop.replace('px', ''))
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - playerDOM.offsetLeft //点击距浏览器左边距离-元素距离浏览器左边距离=元素左边到鼠标点的宽度
const disY = e.clientY - playerDOM.offsetTop //元素上边到鼠标点的高度
const disRight= playerDOM.clientWidth - disX // clientWidth(元素宽度)
const disBottom= playerDOM.clientHeight - disY // clientHeight(元素高度度)
const docWidth=document.documentElement.clientWidth
const docHeight=document.documentElement.clientHeight
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.pageX - disX
const t = e.pageY - disY
// console.log(l+'|'+t)
// console.log(playerDOM.offsetLeft + '|' + playerDOM.offsetTop)
// 移动当前元素
// let lmove = Number(playerDOM.offsetLeft-playerDOM.clientWidth)<0?0:l
// let tmove = Number(playerDOM.offsetTop)<0?0:t
let lmove = l
let tmove = t
if (lmove < 0) {
lmove = 0
}
console.log((e.pageX + disRight) + '|' + docWidth)
if (e.pageX + disRight >= docWidth ) {
lmove = playerDOM.offsetLeft
}
if (tmove < 0) {
tmove = 0
}
if (e.pageY +disBottom >= docHeight ) {
tmove = playerDOM.offsetTop
}
playerDOM.style.left = `${lmove}px`
playerDOM.style.top = `${tmove}px`
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
vue指令版
javascript
//dragMove.js
export default {
bind(el, binding, vnode, oldVnode) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
dialogHeaderEl.onmousedown = (e) => {
const defaultTop = Number(document.defaultView.getComputedStyle(dragDom, null).marginTop.replace('px', ''))
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
// 获取到的值带px 正则匹配替换
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const t = e.clientY - disY
// 移动当前元素
let lmove = l + styL
let tmove = t + styT
const maxLeft = (window.innerWidth - dialogHeaderEl.offsetWidth) / 2
const minTop = defaultTop
const maxTop = window.innerHeight - minTop - dragDom.offsetHeight
if (lmove < -maxLeft) {
lmove = -maxLeft
}
if (lmove > maxLeft) {
lmove = maxLeft
}
if (tmove < -minTop) {
tmove = -minTop
}
if (tmove > maxTop) {
tmove = maxTop
}
dragDom.style.left = `${lmove}px`
dragDom.style.top = `${tmove}px`
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
},
unbind(el) {
const dragDom = el.querySelector('.el-dialog')
dragDom.style.left = `0px`
dragDom.style.top = `0px`
}
}
javascript
//指令注册
import dragMove from './dragMove'
const install = function(Vue) {
Vue.directive('dragMove', dragMove)
}
if (window.Vue) {
window['dragMove'] = dragMove
Vue.use(install)
}
dragMove.install = install
export default dragMove
//全局挂载
Vue.directive('dragMove', dragMove)