记得上篇文章说到过这个问题,今天翻自己以前写的一个demo时,又纠结于这个问题之上。
以下是作为试验对象的HTML:
上网一通好找(上篇文章的方法并不能解决现有的问题,而且远谈不上解决)。
首先是注意到IE特有的两个方法:mouseenter/mouseleave,说实话,我以前还真不知道有这两个方法!
拿来用上,还真行。在IE6试验的时候还真很好的解决了父子元素边界处触发mouseout/mouseover的问题。
但IE可以了,FF呢?opera呢。。。
又是一通好找,终于,传说中的“compareDocumentPosition”出现了,嘿嘿!
下面是从网上找到的关于它的“传说”:
在判断一个节点是否是另一个节点的祖先时
发现有compareDocumentPosition这么个函数
程序里的写法是:return !!(p.compareDocumentPosition(c) & 16);
开始对为什么要&上个16感到奇怪
因为以前没有用过compareDocumentPosition
所以也不知道它返回的值是什么
经过查询资料
以及测试
总结了下compareDocumentPosition返回值的结果
这个方法是用来判断一个节点是另一个节点的后代(10-01010)还是祖先(20-),在前面(4-00100)还是后面(2-0),同一节点为0(00000)
五位的二进制的各个位置表示不同的值:
第五位:祖先 //20
第四位:后代 //10
第三位:前面 //4
第二位:后面 //2
第一位:本身 //0
相匹配的值为1,反之为0
这样对应五种情况,值分别是:10100(20), 01010(10), 00100(4), 00010(2), 00000(0)
即然知道了这些值
前面为什么要&上16
就一目了然了
只有第五位为1的时候,才会返回True,证明一个节点是另一个节点的祖先.
为什么说找到传说哥“compareDocumentPosition”就能解决问题呢?
首先对于mouseover来说:
一个页面元素,通常情况下,只有鼠标从一个非子代元素移动它包括的页面区域时才算作mouseover(这其中也不包括它自己)。
而对于mouseout来说:
一个页面元素,通常情况下,只有鼠标从它自身移动到一个非子代元素包括的页面区域时才算作mouseover(这其中也不包括它自己)。
那么就好说了,由传说哥“compareDocumentPosition”写一个方法:
至于为什么这么写,上面己经说明了。
所以得到了下面能兼容IE的FF的mouseover/mouseout:
运行一下试试,好像并不是很理想,在FF下面还是出现了“边界问题”,这是为什么呢?照道理是可以的啊。
上面的方法“contain”很好的判断了添加了mouseover/mouseout事件的元素和触发事件时event对象所指向的元素间的关系啊,以此为依据判断是没有错的啊。
于是我把思路从新理了一次,发现了一个问题,方法“contain”只判断了两个元素间是否是父子关系,却没有排除一种可能,那就是添加了mouseover/mouseout事件的元素是否就是触发事件时event对象所指向的元素。会不会是这点呢,因为如果是这样,“!contain(this, e.relatedTarget)”返回的就会是true,此时,事件也会被触发。
为了证实这一点,我把方法“contain”改成了下面的判断形式:
这样,如果是父子关系或者是自己的话就会返回true。
而结果正如我想的,在FF下面问题得到了解决,而且在opera10下面也没有出现“边界问题”。
“三口试买旮等”,这个很纠结的问题意算有了一个比较好的解决方案!
不过,事事证明,残缺才叫美,嘿嘿,为什么?
在FF下面,如果外部的input标签紧靠着DIV的话,当你快速的从DIV移过input时,mouseout会失灵(input在DIV内部时不会)。
当然,如果你让它们之间有一定的间距的话就不会了。
很少写文章,一个问题说了这么多,各位有兴看的人千万别拍砖!