欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript DOM 鼠标拖拽

程序员文章站 2022-06-17 10:33:04
在前端页面交互中,鼠标拖拽是一个体验良好的功能,实现鼠标拖拽需要了解鼠标行为坐标系和涉及到的许多兼容性写法。本文介绍鼠标位置的获取和、拽功能的实现以及拖拽函数的封装 ......

javascript dom 鼠标拖拽

在前端页面交互中,鼠标拖拽是一个体验良好的功能,实现鼠标拖拽需要了解鼠标行为坐标系和涉及到的许多兼容性写法。本文介绍鼠标位置的获取和、拽功能的实现以及拖拽函数的封装

鼠标行为坐标系

  1. 鼠标行为触发事件时,事件对象上会有一些属性提供鼠标的位置信息

    属性 功能 兼容性
    clientx/y 鼠标相对可视区域的坐标 /
    x/y 与 clientx/y 功能相同 firefox 低版本不支持
    pagex/y 鼠标相对整个文档的坐标 兼容 ie9 及以上
    layerx/y 与 pagex/y 功能相同 ie10 及以下同 clientx/y
    screenx/y 鼠标位置相对屏幕坐标 /
    offsetx/y 鼠标位置相对块元素的坐标(包含边框) safari 不包含边框
  2. 获取鼠标相对整个文档的坐标:pagex/y 兼容性差,需要进行封装

    鼠标相对整个文档的坐标 = 鼠标相对可视区域的坐标 + 滚动条滚动距离 - 文档偏移

    document.documentelement.clienttop 获取文档偏移,在 ie 一些版本中为 undefined

    function pagepos(ev) {
        var stop = getscrolloffset().top,
            sleft = getscrolloffset().left,
            ctop = document.documentelement.clienttop || 0,
            cleft = document.documentelement.clientleft || 0;
        return {
            x: ev.clientx + sleft - cleft,
            y: ev.clienty + stop - ctop
        }
    }
    // 封装的函数:获取滚动条滚动距离
    function getscrolloffset() {
        if (window.pagexoffset) {
            return {
                top: window.pageyoffset,
                left: window.pagexoffset
            }
        }
        else return {
            top:document.body.scrolltop || document.documentelement.scrolltop,
            left:document.body.scrollleft || document.documentelement.scrollleft
        }
    }
    

拖拽函数封装

  1. 拖拽效果基于鼠标事件:mousedown、mousemove、mouseup

    分别为鼠标按下、鼠标移动、鼠标松开

  2. 原理:鼠标按下时,添加鼠标移动、鼠标松开的事件处理函数,鼠标移动时获取鼠标坐标,改变元素样式,鼠标松开时清除鼠标移动和鼠标松开的事件处理函数

    <!doctype html>
    <html lang="zh">
    <head>
        <meta charset="utf-8">
        <title>index</title>
        <style type="text/css">
            .box {
                position: absolute;
                top: 0;
                left: 0;
                width: 100px;
                height: 100px;
                background-color: red;
            }
        </style>
    </head>
    <body>
    <div class="box"></div>
    <script>
        var box = document.getelementsbytagname('div')[0];
    
        box.onmousedown = function (ev) {
            var ev = ev || window.event,
                x = pagepos(ev).x - parseint(getstyles(box)['left']),
                y = pagepos(ev).y - parseint(getstyles(box)['top']);
    
            document.onmousemove = function (ev) {
                var ev = ev || window.event,
                    mpos = pagepos(ev);
                box.style.left = mpos.x - x + 'px';
                box.style.top = mpos.y - y + 'px';
            }
            document.onmouseup = function () {
                this.onmousemove = null;
                this.onmouseup = null;
            }
        }
    
        // 封装的函数:获取鼠标相对整个文档的坐标
        function pagepos(ev) {
            var stop = getscrolloffset().top,
                sleft = getscrolloffset().left,
                ctop = document.documentelement.clienttop || 0,
                cleft = document.documentelement.clientleft || 0;
            return {
                x: ev.clientx + sleft - cleft,
                y: ev.clienty + stop - ctop
            }
        }
    	// 封装的函数:获取滚动条滚动距离
        function getscrolloffset() {
            if (window.pagexoffset) {
                return {
                    top: window.pageyoffset,
                    left: window.pagexoffset
                }
            } else return {
                top: document.body.scrolltop || document.documentelement.scrolltop,
                left: document.body.scrollleft || document.documentelement.scrollleft
            }
        }
    
        // 封装的函数:获取元素样式的类数组
        function getstyles(elem) {
            if (window.getcomputedstyle) {
                return window.getcomputedstyle(elem, null);
            } else return elem.currentstyle;
        }
    </script>
    </body>
    </html>
    
  3. 封装拖拽函数

    var box = document.getelementsbytagname('div')[0];
    elemdrag(box);
    
    // 封装的拖拽函数
    function elemdrag(elem) {
        var x,
            y;
        addevent(elem, 'mousedown', function (ev) {
            var ev = ev || window.event;
            x = pagepos(ev).x - parseint(getstyles(elem)['left']);
            y = pagepos(ev).y - parseint(getstyles(elem)['top']);
            addevent(document, 'mousemove', mousemove);
            addevent(document, 'mouseup', mouseup);
            cancelbubble(ev);
            preventdefaultevent(ev);
        });
    
        function mousemove(ev) {
            var ev = ev || window.event;
            elem.style.left = pagepos(ev).x - x + 'px';
            elem.style.top = pagepos(ev).y - y + 'px';
        }
    
        function mouseup(ev) {
            var ev = ev || window.event;
            removeevent(document, 'mousemove', mousemove);
            removeevent(document, 'mouseup', mouseup);
        }
    
    }
    // 绑定事件处理函数
    function addevent(elem, type, fn) {
        if (elem.addeventlistener) {
            elem.addeventlistener(type, fn);
        } else if (elem.attachevent) {
            elem.attachevent('on' + type, function (ev) {
                fn.call(elem, ev); // call 兼容性比 bind 好
            });
        } else {
            elem['on' + type] = fn;
        }
    }
    // 解绑事件处理函数
    function removeevent(elem, type, fn) {
        if (elem.addeventlistener) {
            elem.removeeventlistener(type, fn);
        } else if (elem.attachevent) {
            elem.detachevent('on' + type, fn);
        } else {
            elem['on' + type] = null;
        }
    }
    // 获取鼠标在整个文档中的坐标
    function pagepos(ev) {
        var stop = getscrolloffset().top,
            sleft = getscrolloffset().left,
            ctop = document.documentelement.clienttop || 0,
            cleft = document.documentelement.clientleft || 0;
        return {
            x: ev.clientx + sleft - cleft,
            y: ev.clienty + stop - ctop
        }
    }
    // 获取滚动条滚动距离
    function getscrolloffset() {
        if (window.pagexoffset) {
            return {
                top: window.pageyoffset,
                left: window.pagexoffset
            }
        } else return {
            top: document.body.scrolltop || document.documentelement.scrolltop,
            left: document.body.scrollleft || document.documentelement.scrollleft
        }
    }
    // 获取元素样式的类数组
    function getstyles(elem) {
        if (window.getcomputedstyle) {
            return window.getcomputedstyle(elem, null);
        } else return elem.currentstyle;
    }
    // 阻止冒泡
    function cancelbubble(ev) {
        if (ev.stoppropagation) {
            ev.stoppropagation();
        } else ev.cancelbubble = true; // 兼容 ie8 及以下
    }
    // 阻止默认事件
    function preventdefaultevent(ev) {
        if (ev.preventdefault) {
            ev.preventdefault();
        } else ev.returnvalue = false; // 兼容 ie8 及以下
    }