DOM-15【鼠标事件深入-点击与拖拽分离-双击事件-协作开发】

本文深入探讨了JavaScript中鼠标的事件顺序,如mousedown、mouseup和click,并介绍了如何实现点击与拖拽的分离。通过示例展示了如何创建模块化拖放功能,包括限制元素拖动范围、处理右键菜单和双击事件。此外,还讨论了在多人协作开发中编写可复用插件的方法。
摘要由CSDN通过智能技术生成

一、鼠标事件深入

(1)执行顺序

mousedown > mouseup > click

(2)鼠标对应的码

  1. 左键 = 0
  2. 中间 = 1
  3. 右键 = 2
    在这里插入图片描述
    事件对象的button属性里面可以访问

二、点击与拖拽分离

(1)模块的两种写法

等待执行的模块

var dragNclick = (function (a, b) {
    console.log(a, b);
})

dragNclick(1, 2)

立即执行的模块

init();

function init() {
    dragNclick;
}

var dragNclick = (function (a, b) {
    console.log(a, b);
})(1, 2);

(2)模块拖动案例

业务需求:

  1. 点击的时候跳转
  2. 拖动鼠标抬起的时候不跳转
  3. 鼠标拖动并跳转链接的时候回到原位

等待执行模块化

var dragNclcik = (function (elem, elemclick) {

    var bTime = 0, // 记录点击时间
        eTime = 0,
        oPos = []; // 记录原先位置

    drag();

    function drag() {
        var x,
            y;

        addEvent(elem, 'mousedown', function (e) {
            var e = e || window.event;
            bTime = new Date().getTime();
            oPos = [getStyles(elem, 'left'), getStyles(elem, 'top')]
            x = pagePos(e).X - getStyles(elem, 'left');
            y = pagePos(e).Y - getStyles(elem, 'top');

            addEvent(document, 'mousemove', mouseMove);
            addEvent(document, 'mouseup', mouseUp);
            cancleBubble(e);
            preventDefaultEvent(e);
        })

        function mouseMove(e) {
            var e = e || window.event;

            elem.style.top = pagePos(e).Y - y + 'px';
            elem.style.left = pagePos(e).X - x + 'px';
        }

        function mouseUp(e) {
            var e = e || window.event;
            eTime = new Date().getTime();

            console.log(eTime - bTime);
            console.log(oPos[0]);


            if (eTime - bTime < 100) {
                elem.style.left = oPos[0] + 'px';
                elem.style.top = oPos[1] + 'px';
                elemclick();
            }
            removeEvent(document, 'mousemove', mouseMove);
            removeEvent(document, 'mouseup', mouseUp);
        }
    }
})

执行调用:

<script type="text/javascript">
    var oLink = document.getElementsByTagName('a')[0];
    dragNclcik(oLink, function () {
        window.open('http://www.baidu.com');
    });
</script>

写到原形上面

Element.prototype.dragNclcik = (function (elemclick) {

    var bTime = 0, // 记录点击时间
        eTime = 0,
        oPos = []; // 记录原先位置

    drag.call(this);

    function drag() {
        var x,
            y,
            _self = this;

        addEvent(_self, 'mousedown', function (e) {
            var e = e || window.event;
            bTime = new Date().getTime();
            oPos = [getStyles(_self, 'left'), getStyles(_self, 'top')]
            x = pagePos(e).X - getStyles(_self, 'left');
            y = pagePos(e).Y - getStyles(_self, 'top');

            addEvent(document, 'mousemove', mouseMove);
            addEvent(document, 'mouseup', mouseUp);
            cancleBubble(e);
            preventDefaultEvent(e);
        })

        function mouseMove(e) {
            var e = e || window.event;

            _self.style.top = pagePos(e).Y - y + 'px';
            _self.style.left = pagePos(e).X - x + 'px';
        }

        function mouseUp(e) {
            var e = e || window.event;
            eTime = new Date().getTime();

            console.log(eTime - bTime);
            console.log(oPos[0]);


            if (eTime - bTime < 100) {
                _self.style.left = oPos[0] + 'px';
                _self.style.top = oPos[1] + 'px';
                elemclick();
            }
            removeEvent(document, 'mousemove', mouseMove);
            removeEvent(document, 'mouseup', mouseUp);
        }
    }
})

执行调用:

<script type="text/javascript">
    var oLink = document.getElementsByTagName('a')[0];
    oLink.dragNclcik(function () {
        window.open('http://www.baidu.com');
    });
</script>

注意: this指向问题

模块边界问题

Element.prototype.dragNclcik = (function (elemclick) {

    var bTime = 0, // 记录点击时间
        eTime = 0,
        oPos = [], // 记录原先位置
        wWidth = getViewportSize().width,
        wHeight = getViewportSize().height,
        elemWidth = getStyles(this, 'width'),
        elemHeight = getStyles(this, 'height');

    drag.call(this);

    function drag() {
        var x,
            y,
            _self = this;

        addEvent(_self, 'mousedown', function (e) {
            var e = e || window.event;
            bTime = new Date().getTime();
            oPos = [getStyles(_self, 'left'), getStyles(_self, 'top')]
            x = pagePos(e).X - getStyles(_self, 'left');
            y = pagePos(e).Y - getStyles(_self, 'top');

            addEvent(document, 'mousemove', mouseMove);
            addEvent(document, 'mouseup', mouseUp);
            cancleBubble(e);
            preventDefaultEvent(e);
        })

        function mouseMove(e) {
            var e = e || window.event,
                elemLeft = pagePos(e).X - x,
                elemTop = pagePos(e).Y - y;

            if (elemLeft <= 0) {
                elemLeft = 0;
            } else if (elemLeft >= wWidth - elemWidth) {
                elemLeft = wWidth - elemWidth - 1;  // 避免误差
            }

            if (elemTop <= 0) {
                elemTop = 0;
            } else if (elemTop >= wHeight - elemHeight) {
                elemTop = wHeight - elemHeight - 1;
            }

            _self.style.top = elemTop + 'px';
            _self.style.left = elemLeft + 'px';
        }

        function mouseUp(e) {
            var e = e || window.event;
            eTime = new Date().getTime();

            console.log(eTime - bTime);
            console.log(oPos[0]);


            if (eTime - bTime < 100) {
                _self.style.left = oPos[0] + 'px';
                _self.style.top = oPos[1] + 'px';
                elemclick();
            }
            removeEvent(document, 'mousemove', mouseMove);
            removeEvent(document, 'mouseup', mouseUp);
        }
    }
})

执行调用:

<script type="text/javascript">
    var oLink = document.getElementsByTagName('a')[0];
    oLink.dragNclcik(function () {
        window.open('http://www.baidu.com');
    });
</script>

右击菜单边界问题

Element.prototype.dragNclcik = (function (menu, elemclick) {

    var bTime = 0, // 记录点击时间
        eTime = 0,
        oPos = [], // 记录原先位置
        wWidth = getViewportSize().width,
        wHeight = getViewportSize().height,
        elemWidth = getStyles(this, 'width'),
        elemHeight = getStyles(this, 'height'),
        mWidth = getStyles(menu, 'width'),
        mHeight = getStyles(menu, 'height');

    drag.call(this);

    function drag() {
        var x,
            y,
            _self = this;

        addEvent(_self, 'mousedown', function (e) {
            var e = e || window.event,
                btnCode = e.button;
            if (btnCode === 2) {
                var mLeft = pagePos(e).X,
                    mTop = pagePos(e).Y;

                if (mLeft <= 0) {
                    mLeft = 0;
                } else if (mLeft >= wWidth - mWidth) {
                    mLeft = pagePos(e).X - mWidth;
                }

                if (mTop <= 0) {
                    mTop = 0;
                } else if (mTop >= wHeight - mHeight) {
                    mTop = pagePos(e).Y - mHeight;
                }

                menu.style.left = mLeft + 'px';
                menu.style.top = mTop + 'px';
                menu.style.display = 'block';

            } else if (btnCode === 0) {
                bTime = new Date().getTime();
                oPos = [getStyles(_self, 'left'), getStyles(_self, 'top')]
                menu.style.display = 'none';

                x = pagePos(e).X - getStyles(_self, 'left');
                y = pagePos(e).Y - getStyles(_self, 'top');

                addEvent(document, 'mousemove', mouseMove);
                addEvent(document, 'mouseup', mouseUp);
                cancleBubble(e);
                preventDefaultEvent(e);
            }

        })

        addEvent(document, 'contextmenu', function (e) {
            var e = e || window.event;
            preventDefaultEvent(e);
        })

        addEvent(document, 'click', function (e) {
            menu.style.display = 'none';
        })

        addEvent(menu, 'click', function (e) {
            cancleBubble(e)
        })

        function mouseMove(e) {
            var e = e || window.event,
                elemLeft = pagePos(e).X - x,
                elemTop = pagePos(e).Y - y;

            if (elemLeft <= 0) {
                elemLeft = 0;
            } else if (elemLeft >= wWidth - elemWidth) {
                elemLeft = wWidth - elemWidth - 1;  // 避免误差
            }

            if (elemTop <= 0) {
                elemTop = 0;
            } else if (elemTop >= wHeight - elemHeight) {
                elemTop = wHeight - elemHeight - 1;
            }

            _self.style.top = elemTop + 'px';
            _self.style.left = elemLeft + 'px';
        }

        function mouseUp(e) {
            var e = e || window.event;
            eTime = new Date().getTime();

            console.log(eTime - bTime);
            console.log(oPos[0]);


            if (eTime - bTime < 100) {
                _self.style.left = oPos[0] + 'px';
                _self.style.top = oPos[1] + 'px';
                elemclick();
            }
            removeEvent(document, 'mousemove', mouseMove);
            removeEvent(document, 'mouseup', mouseUp);
        }
    }
})

执行调用:

<script type="text/javascript">
    var oLink = document.getElementsByTagName('a')[0],
        oMenu = document.getElementsByTagName('div')[0];
    oLink.dragNclcik(oMenu, function () {
        window.open('http://www.baidu.com');
    });
</script>

三、双击事件

Element.prototype.dragNclcik = (function (menu, elemclick) {

    var bTime = 0, // 记录点击时间
        eTime = 0,
        oPos = [], // 记录原先位置
        cbTime = 0,
        ceTime = 0,
        counter = 0,
        t = null,
        wWidth = getViewportSize().width,
        wHeight = getViewportSize().height,
        elemWidth = getStyles(this, 'width'),
        elemHeight = getStyles(this, 'height'),
        mWidth = getStyles(menu, 'width'),
        mHeight = getStyles(menu, 'height');

    drag.call(this);

    function drag() {
        var x,
            y,
            _self = this;

        addEvent(_self, 'mousedown', function (e) {
            var e = e || window.event,
                btnCode = e.button;
            if (btnCode === 2) {
                var mLeft = pagePos(e).X,
                    mTop = pagePos(e).Y;

                if (mLeft <= 0) {
                    mLeft = 0;
                } else if (mLeft >= wWidth - mWidth) {
                    mLeft = pagePos(e).X - mWidth;
                }

                if (mTop <= 0) {
                    mTop = 0;
                } else if (mTop >= wHeight - mHeight) {
                    mTop = pagePos(e).Y - mHeight;
                }

                menu.style.left = mLeft + 'px';
                menu.style.top = mTop + 'px';
                menu.style.display = 'block';

            } else if (btnCode === 0) {
                bTime = new Date().getTime();
                oPos = [getStyles(_self, 'left'), getStyles(_self, 'top')]
                menu.style.display = 'none';

                x = pagePos(e).X - getStyles(_self, 'left');
                y = pagePos(e).Y - getStyles(_self, 'top');

                addEvent(document, 'mousemove', mouseMove);
                addEvent(document, 'mouseup', mouseUp);
                cancleBubble(e);
                preventDefaultEvent(e);
            }

        })

        addEvent(document, 'contextmenu', function (e) {
            var e = e || window.event;
            preventDefaultEvent(e);
        })

        addEvent(document, 'click', function (e) {
            menu.style.display = 'none';
        })

        addEvent(menu, 'click', function (e) {
            cancleBubble(e)
        })

        function mouseMove(e) {
            var e = e || window.event,
                elemLeft = pagePos(e).X - x,
                elemTop = pagePos(e).Y - y;

            if (elemLeft <= 0) {
                elemLeft = 0;
            } else if (elemLeft >= wWidth - elemWidth) {
                elemLeft = wWidth - elemWidth - 1;  // 避免误差
            }

            if (elemTop <= 0) {
                elemTop = 0;
            } else if (elemTop >= wHeight - elemHeight) {
                elemTop = wHeight - elemHeight - 1;
            }

            _self.style.top = elemTop + 'px';
            _self.style.left = elemLeft + 'px';
        }

        function mouseUp(e) {
            var e = e || window.event;
            eTime = new Date().getTime();

            if (eTime - bTime < 200) {
                _self.style.left = oPos[0] + 'px';
                _self.style.top = oPos[1] + 'px';

                counter++;

                if (counter === 1) {
                    cbTime = new Date().getTime();
                }

                if (counter === 2) {
                    ceTime = new Date().getTime();
                }

                if (cbTime && ceTime && (ceTime - cbTime < 200)) {
                    console.log(ceTime - cbTime, counter);
                    elemclick();
                }

                t = setTimeout(function () {
                    cbTime = 0;
                    ceTime = 0;
                    counter = 0;
                    clearTimeout(t)
                }, 500);

            }

            removeEvent(document, 'mousemove', mouseMove);
            removeEvent(document, 'mouseup', mouseUp);
        }
    }
})

执行调用:

<script type="text/javascript">
    var oLink = document.getElementsByTagName('a')[0],
        oMenu = document.getElementsByTagName('div')[0];
    oLink.dragNclcik(oMenu, function () {
        window.open('http://www.baidu.com');
    });
</script>

(1)为什么要清除计时器?

因为计时器是保存在内存里面的,不用了把它清除是一种好习惯

(2)为什么要清零

cbTime = 0;
ceTime = 0;
counter = 0;

因为你点击第一次的时候会保存cbTime

第二次点击会保存ceTime

但是如果ceTime - cbTime ≮ 200的话,cbTime、ceTime、counter就不会清零,也不会执行函数

往后点counter就会从2一直往后加,往后加就不会重新获取时间戳,然后cbTime、ceTime一直都是固定的,而且ceTime - cbTime ≮ 200,就一直进入不到if语句里面

所以要进行清零,因为当ceTime - cbTime ≮ 200的时候,就可以重新获取时间戳,然后计算它们的差值

(3)为什么要用延时器清零?

t = setTimeout(function () {
    cbTime = 0;
    ceTime = 0;
    counter = 0;
    clearTimeout(t)
}, 500);

因为当你只点击了一次的时候,它没有清除,然后下一次双击的时候就会出现问题,因为counter是从第一次点击时开始计算的,就是从1开始加,加到2、3,当你第二次进行双击的时候ceTime - cbTime 肯定就大于 200毫妙了,然后就进入不到if语句,只要counter不清零,就永远不会重新获取时间戳,不重新获取时间戳就无法重新计算ceTime - cbTime,就进入不到语句。

所以设置延时器清零,就是为当你只点击了1次的情况,它会延迟500毫妙自动给你清零,然后你下一次双击的时候,就可以重新获取时间戳,重新计算ceTime - cbTime,从而进入语句。

四、多人协作开发插件

; (function () {

    var Test = function (opt) {
        this.num1 = opt.num1;
        this.num2 = opt.num2;
        this.btnGroup = opt.btnGroup;
    }

    Test.prototype = {
        // 执行bindEvent
        init: function () {
            this.bindEvent();
        },
        // 写所有的事件、事件处理函数
        bindEvent: function () {
            var btns = this.btnGroup,
                _self = this;

            addEvent(btns, 'click', function (e) {
                _self.compute.call(_self, e)
            })
        },
        // 自己写的插件
        compute: function (e) {
            var e = e || window.event,
                tar = e.target || e.srcElement,
                val1 = parseInt(this.num1.value),
                val2 = parseInt(this.num2.value),
                btns = this.btnGroup,
                sign;

            sign = tar.getAttribute('data-sign')

            switch (sign) {
                case 'plus':
                    console.log(val1 + val2);
                    break;
                case 'minus':
                    console.log(val1 - val2);
                    break;
                case 'mul':
                    console.log(val1 * val2);
                    break;
                case 'div':
                    console.log(val1 / val2);
                    break;
                default:
                    console.log('出错了');
            }

        }

    }

    window.Test = Test;

})()

执行调用:

<script type="text/javascript">
    var test = new Test({
        num1: document.getElementById('num1'),
        num2: document.getElementById('num2'),
        btnGroup: document.getElementsByClassName('btn-group')[0]
    }).init(); // 启用插件
</script>

(1)this访问问题

方法一:提升到封闭作用域的最顶端

; (function () {
    var _self;
    
    var Test = function (opt) {
        _self = this;
    }
    
    Test.prototype = {
    
    }
    
    window.Test = Test;
})()

方法二:call/apply执行事件处理函数里面的函数

bindEvent: function () {
    var btns = this.btnGroup,
        _self = this;

    addEvent(btns, 'click', function (e) {
        _self.compute.call(_self, e)
    })
}

(2)init & bindEvent

这两个是写在原形上面的,init用来控制插件是否执行,bindEvent里面放所有的事件处理函数,init里面写执行bindEvent方法

五、作业

(1)windows桌面

在这里插入图片描述

要求:

  1. 写四个图标可以随意拖动
  2. 鼠标hover到图标上面的时候有一个透明的背景,点击的时候聚集
  3. 右键图标会有一个菜单
  4. 点击这个图标会弹出来一个窗口,可以关闭这个窗口
  5. 桌面底部写一个任务栏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值