中国第一Ajax站长门户:www.okajax.com   虚拟主机 域名注册 云主机

javascript页面拖动效果的分析(4) - okajax.com - Ajax中国

我要投稿 会员登陆 RSS订阅 本站推荐:
您的位置主页 > Ajax技术 > Ajax技巧教程 > javascript页面拖动效果的分析(4)

javascript页面拖动效果的分析(4)

2008-11-24    文章来源:互联网    浏览次数:

默认动作

对选择状态的文本内容、连接和图片等进行拖放操作会触发系统的默认动作,例如ie中拖动图片鼠标会变成禁止操作状态,这样会导致这个拖放程序执行失败。

不过ie在设置了setCapture之后,通过用户界面用鼠标进行拖放操作和内容选择都会被禁止。
意思就是setCapture之后就不能对文档内容进行拖放和选择,注意这里的拖放是指系统的默认动作,例如ondragstart就不会被触发。
不过如果setCapture的参数是false的话,容器内的对象还是可以触发事件的(具体看鼠标捕获部分),所以setCapture的参数要设成true或保留默认值。

而ff的鼠标捕获没有这个功能,但可以用preventDefault来取消事件的默认动作来解决:

oEvent.preventDefault();

ps:据说使用preventDefault会出现mouseup丢失的情况,但我在ff3中测试没有发现,如果各位发现任何mouseup丢失的情况,务必告诉我啊。

清除选择

ie在设置setCapture之后内容选择都会被禁止,但也因此不会清除在设置之前就已经选择的内容,而且设置之后也能通过其他方式选择内容,
例如用ctrl+a来选择内容。
ps:onkeydown、onkeyup和onkeypress事件不会受到鼠标捕获影响。
而ff在mousedown时就能清除原来选择的内容,但拖动鼠标,ctrl+a时还是会继续选择内容。
不过在丢弃了系统默认动作之后,这样的选择并不会对拖放操作造成影响,这里设置主要还是为了更好的体验。

以前我用禁止拖放对象被选择的方法来达到目的,即ie中设置拖放对象的onselectstart返回false,在ff中设置样式MozUserSelect(css:-moz-user-select)为none。
但这种方法只能禁止拖放对象本身被选择,后来找到个更好的方法清除选择,不但不影响拖放对象的选择效果,还能对整个文档进行清除:

  • ie: document.selection.empty()
  • ff: window.getSelection().removeAllRanges()

为了防止在拖放过程中选择内容,所以把它放到Move程序中,下面是兼容的写法:

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

margin

还有一个情况,当拖放对象设置了margin,那么拖放的时候就会错位(给SimpleDrag的拖放对象设置margin就可以测试)。
原因是在Start程序设置_x和_y时是使用offset获取的,而这个值是包括margin的,所以在设置left和top之前要减去这个margin。
但如果在Start程序中就去掉margin那么在Move程序中设置范围限制时就会计算错误,
所以最好是在Start程序中获取值:

this._marginLeft = parseInt(CurrentStyle(this.Drag).marginLeft) || 0;
this._marginTop = parseInt(CurrentStyle(this.Drag).marginTop) || 0;

其中CurrentStyle是用来获取最终样式,详细看这里的最终样式部分。

在Move程序中设置值:

this.Drag.style.left = iLeft - this._marginLeft + "px";
this.Drag.style.top = iTop - this._marginTop + "px";

要注意margin要在范围修正只后再设置,否则会错位。

【透明背景bug】

在ie有一个透明背景bug(不知算不算bug),可以用下面的代码测试:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<div onmousedown="alert(1)" style="border:10px solid #C4E3FD; width:50px; height:50px;position:absolute;"> </div>
</body>
</html>

会发现背景点击触发不了事件,不过点击边框的话还是可以触发。
为什么呢?再用下面的代码测试:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body style="border:1px solid #FF0000;">
<style>div{width:100px; height:100px; border:1px solid #000;} </style>
<div style="position:relative;">
<div onclick="alert(1)" style="border-color:#00f;margin:50px;"> </div>
<div onclick="alert(2)" style="border-color:#6f0;position:absolute;top:50px;"> </div>
</div>
</body>
</html>

应该能看出个大概了,下面两个div超出body(即超出红色框)的部分就触发不了事件。
也就是说当触发事件的点,在body以外,而背景又是透明的,那么就会误认为触发点是在了body外空白的地方,所以触发不了事件。
那解决的方法就是,使事件触发点保持在body内,或者设置一个非透明背景。

那程序中只要给拖放对象设一个背景色就可以解决了,但有时需求正好是要透明(例如切割效果),那怎么办呢?
首先想到的是加上背景色后设置完全透明,但这样连边框,容器内的对象等都完全透明了,这个不好。
我想到的一个解决方法是在容器里面加一个层,覆盖整个容器,并设置背景色和完全透明:

with(this._Handle.appendChild(document.createElement("div")).style){
width = height = "100%"; backgroundColor = "#fff"; filter = "alpha(opacity:0)";
}

当发现程序有这个bug出现,把程序可选参数Transparent设为true就会自动插入这样一个层了。
各位如果有更好的方法请多多指点。

暂时就研究到这里,不过还有iframe,滚屏等这些还没考虑到,等以后有需要了再来研究拉。

原文地址:http://www.cnblogs.com/cloudgamer/archive/2008/11/17/1334778.html

  • 第1页:javascript实现拖动的原理
  • 第2页:拖拽锁定、释放以及范围限制
  • 第3页:鼠标捕获、焦点丢失
  • 第4页:默认动作、清除选择
  • 文章评论(查看全部)

    看不清楚?单击换一张。
    loading.. 评论加载中....
    关于我们 - 广告服务 - 版权隐私 - 免责声明 - RSS地图 - 网站地图 - 使用帮助 - 返回顶部