JS简单拖放程序

在大学做web应用时,就搞过拖放,当时从网上搜索的相关程序,感觉代码很复杂,最终效果还不好,自己也没调通,所以在脑子里总感觉拖放是很复杂的东西。最近正好有时间,再写下这种程序。

要实现拖放,基本思路就是:鼠标点下时监听移动,抬起时停止监听。

        var x,y;
        function move(e) {
            el.style.left = e.clientX - x + 'px';
            el.style.top =  e.clientY - y + 'px';
        }

        function stop() {
            E.detach(document, 'mousemove', move);
            E.detach(document, 'mouseup', stop);
        }
        E.on(el, 'mousedown', function(e) {

            x = e.clientX - el.offsetLeft;
            y = e.clientY - el.offsetTop;
            E.on(document, 'mousemove', move);
            E.on(document, 'mouseup', stop);

        });

这样拖放就实现了,当然还有一些问题:

拖放禁止

1.当第一次拖放后,再次拖放元素就会发现会出现拖放禁止图标,是因为第一次拖放时点击拖放元素,拖放元素被选择,第二次拖放时使用了浏览器默认拖放。浏览器对于 image,link,selection默认是可以拖放的。

2.拖放过程中移动到其他元素时,其他元素被选择,再次拖放也会出现拖放禁止图标,原因同上。

解决这个问题:

方法一:preventDefault

问题1,在mousedown中阻止默认动作,防止元素被选择;问题2,在mousemove中阻止默认动作,防止其他元素被选择(opera貌似无效)。

这个方法有点体验不足:在ie9,ff等现代浏览器将 “清除之前选择”的默认动作也阻止了,如果之前有选择内容,拖放时原选择不会被清除。

方法二:清空 selection

mousedown,mousemove的时候清空一下selection即可解决上面两个问题

有的程序也通过setCapture来阻止默认事件,并且扩大捕获,兼容性不好不考虑;

综合考虑,采用清空selection比较好。

异常终止问题

1.窗口失去焦点时(如:alt+tab切换,alert等),无法触发mouseup(chrome 可以触发),导致拖放不终止,回到窗口时继续拖放,体验不好

2.页面中存在iframe时,鼠标移动到iframe中事件传递到iframe的document中,无法到达原来的document导致无法触发mouseup,mousemove等

解决第一个问题,可以监听下window blur事件,终止拖放;但这里有个问题:ie通过document.selection.empty()方法清除selection,当selection有内容时,导致window触发blur事件,拖放终止。这个触发是在mousedown处理完之后触发的,即window blur注册之后再触发,解决可以考虑setTimeout延时注册下。

解决第二个问题,考虑将事件仍传递到本页面document,可以建个遮罩层将iframe遮挡(为了简洁,这里不实现)。

这样简单的拖放程序就出来了,demo,code:

function Drag(el) {
    this.el = el;
    this._initEvents();
}

Drag.prototype = {
    moveTo : function(x, y) {
        var el = this.el;
        el.style.left = x + 'px';
        el.style.top = y + 'px';
    },
    _initEvents : function() {

        var x,y,self = this,el = this.el;

        function move(e) {
            // 防止移动过程中选择其他元素,保证体验一致
            util.clearSelection();
            self.moveTo(e.clientX - x, e.clientY - y);
        }

        function stop() {
            E.detach(document, 'mousemove', move);
            E.detach(document, 'mouseup', stop);
            E.detach(window, 'blur', stop);
        }

        E.on(this.el, 'mousedown', function(e) {

            // 清除之前选择,防止拖拽时禁止
            util.clearSelection();

            var style = util.getComputeStyle(el);
            x = e.clientX - el.offsetLeft + (parseInt(style.marginLeft) || 0);
            y = e.clientY - el.offsetTop + (parseInt(style.marginTop) || 0);

            E.on(document, 'mousemove', move);
            E.on(document, 'mouseup', stop);
            // 失去焦点时终止   document.selection.empty() 会触发blur,延时注册
            setTimeout(function(){E.on(window, 'blur', stop);},0);
        });
    }
};

如果要做成组件,当然还需要考虑全面一些,如:iframe情况,移动范围,非绝对定位元素,移动元素和控制元素不同,相关事件支持等等。现在回头看看实现不复杂,只是遇到问题时自己跑偏了,之前看过《JavaScript 拖放效果》这篇文章,觉得很多问题需要处理,然后写的时候遇到问题就去看文中的介绍,而并没真正从问题本身和解决方法上入手,结果严重影响了效率,而且弄的晕头转向,不知在为了解决什么问题而加代码。有参考固然是好的,但是需要更多的独立思考,理清思路,关注本质,这样程序才能得心应手,才是自己的程序。

 

发表于:2011/08/09 04:07 | 97 views | 发表评论

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

回顶部