Re: 关于Mouse事件的一些测试

看到一個相關的 bug,分享一下:

《Stricter Specifications on Mouse Events Specifically primary,
auxillary, and secondary default actions》

https://www.w3.org/Bugs/Public/show_bug.cgi?id=8406

(12/03/20 3:38), John Hax wrote:
> 总结一下我的建议:
> 
> DOM Level 3 Event 规范(
> http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html)应该:
> 
> 1. 明确只有左键才触发click事件,中键和右键不应触发click事件。修改关于click的default action的说明。
> 
> 2. 收入contextmenu事件,与click事件并列。这两个事件的接口可改为MouseContextEvent之类的名字(extends
> MouseEvent),并且增加一个属性relatedEvent(或者类似的名字),其值为引起该事件的设备事件,如MouseEvent或KeyboardEvent或TouchEvent或null(表示由脚本触发,比如调用click()引起)。
> 
> 3.   可考虑增加mouseclick事件,作为真正的mouse
> click事件(和mouseup/mousedown/dblclick一样是纯鼠标设备事件)。原先click的default
> action说明适用于此事件。
> 
> 2012/3/20 John Hax <johnhax@gmail.com>
> 
>> 右键行为一向是比较坑爹的。
>>
>> 我记得很久很久以前(2001年到2002年左右)在w3c的讨论列表里看过一个针对Firefox的右键行为的讨论。最主要的问题在于,大量网页直接写:<div
>> onclick="window.open(...)">,即用onclick来替代一般的链接跳转或打开新窗口的动作。显然,绝大多数这样的脚本在onclick事件处理器中并不会去判断event.button,而他们的本意是只针对左键点击。因此如果右键触发click事件,就导致非期望的结果。
>>
>> IE(以及后来的Chrome等)应该就是因为这个原因而选择不让右键触发click事件。
>>
>>
>> Firefox的开发者则选择了一条折中路线。即,仍然触发click事件,但是只在document(以及window)上触发,而在其他元素上不触发。因为“伪按钮”动作通常都是注册在元素上的,所以这样既避免了右键触发click事件,又保留了全局捕捉包括右键在内的click事件的能力。
>>
>> 当时我对Firefox开发者的这样一种巧妙折中不禁由衷赞叹,因此对此事印象非常深刻,一直记忆至今。
>>
>> (至于提到的第二个差异,其实是因为FF阻止了右键click的默认行为——即触发contextmenu事件。所以并不成为问题。)
>>
>>
>> 今天重新回顾这个问题,我也要补充一些新的看法。
>>
>> IE因为很早(IE
>> 5.5?)就提供了oncontextmenu事件,因此仅从给开发者提供的特性角度来说,并不需要保留通过click事件来处理右键的能力。而FF当时还没有contextmenu事件,或者至少加入contextmenu事件与做出这样的折中处理是在差不多的时间,况且contextmenu事件当时是一个非标准的IE专有事件,再加上当时的DOM
>> Events Level
>> 2规范其实要求右键应触发click事件(尽管对此有不同解读,但我认为标准的意思是应该触发),因此不得已做出这样的折中。这样的折中确实非常巧妙,但是毕竟是一个违背统一性的特例。
>>
>>
>> 从今天的web开发情况来看,我们仍然在写onclick="xxx"并且从来不在里面检测button值。而click事件本身也从一个鼠标事件变为更接近device
>> independent的一般性的activate事件,比如在链接上按Enter也会触发click事件。【注:在DOM规范里原先是加入了DOMActivate事件,但是由于各种原因,实际上这个事件并没有人使用,大家还是用click了。】
>>
>> 另一方面,我们也有了contextmenu事件,且该事件也是一个device
>> independent事件,如按键盘上的contextmenu按键也能触发该事件。
>>
>>
>> 因此从今天来看,我认为比较好的方式是IE/Chrome的方式。而DOM
>> Events标准应该做的是,将click事件和contextmenu事件对应列出(目前DOM
>> Events标准没有收入contextmenu事件),并说明其并非普通的MouseEvent,而是特殊的事件(我个人想了个名字如MouseContextEvent?)。
>>
>> 目前还存在一个问题就是IE/Chrome左键触发click,右键不触发,但是中键也会触发click。个人认为这个行为是有问题的,只是因为中键用的少而不太有人关注。应该像FF一样,中键不触发click(虽然FF会在document/window上触发)。即使是在a元素上,中键常常是在新窗口/Tab打开链接,也许可视为一种特殊的activate动作。但是考虑到click事件的实际用法,我仍然认为中键触发click是不恰当的。DOM
>> Events标准应该对此予以说明。
>>
>>
>>
>>
>> 2012/3/16 Gray Zhang <otakustay@gmail.com>
>>
>>>   根据昨天在#javascript罗浮宫2群#与@可乐
>>> 同学的讨论,浏览器在处理鼠标右键的MosueEvent序列时存在一些不同,在此摘录并邀请大家讨论:
>>>
>>> 测试页面如下:
>>>
>>>
>>> <!DOCTYPE html>
>>> <html>
>>> <head>
>>> <meta charset="utf-8" />
>>>     <title>Hello World</title>
>>> </head>
>>> <body>
>>>     <div style="width: 400px; height: 400px; background: red;"></div>
>>>     <script>
>>>         var div = document.getElementsByTagName('div')[0];
>>>         div.addEventListener('mousedown', function() {
>>> console.log('mousedown on div'); }, false);
>>>         div.addEventListener('up', function() { console.log('mousedown on
>>> div'); }, false);
>>>         div.addEventListener('click', function() { console.log('mousedown
>>> on div'); }, false);
>>>         div.addEventListener('contextmenu', function() {
>>> console.log('mousedown on div'); }, false);
>>>         document.addEventListener('mousedown', function() {
>>> console.log('mousedown on document'); }, false);
>>>         document.addEventListener('up', function() {
>>> console.log('mousedown on document'); }, false);
>>>         document.addEventListener('click', function() {
>>> console.log('mousedown on document'); }, false);
>>>         document.addEventListener('contextmenu', function() {
>>> console.log('mousedown on document'); }, false);
>>>     </script>
>>> </body>
>>> </html>
>>>
>>> 在红色的<div>元素上右键单击一次后,出现的事件顺序在各浏览器中如下:
>>>
>>> Chrome 17:
>>> mousedown on div
>>> mousedown on document
>>> mouseup on div
>>> mouseup on document
>>> contextmenu on div
>>> contextmenu on document
>>>
>>> Firefox 11:
>>> mousedown on div
>>> mousedown on document
>>> mouseup on div
>>> mouseup on document
>>> click on document
>>> contextmenu on div
>>> contextmenu on document
>>>
>>> IE 9:
>>> mousedown on div
>>> mousedown on document
>>> mouseup on div
>>> mouseup on document
>>> contextmenu on div
>>> contextmenu on document
>>>
>>>
>>> 可以看到,Chrome和IE行为相同,而Firefox会额外在document上触发一个click事件,且该事件不捕获(有使用useCapture参数测试)不冒泡。
>>>
>>> 如果给所有的事件处理函数加上preventDefault行为,则各浏览器中的结果如下:
>>>
>>> Chrome 17:
>>> mousedown on div
>>> mousedown on document
>>> mouseup on div
>>> mouseup on document
>>> contextmenu on div
>>> contextmenu on document
>>> 不弹出菜单
>>>
>>> Firefox 11:
>>> mousedown on div
>>> mousedown on document
>>> mouseup on div
>>> mouseup on document
>>> click on document
>>> 不弹出菜单
>>>
>>> IE 9:
>>> mousedown on div
>>> mousedown on document
>>> mouseup on div
>>> mouseup on document
>>> contextmenu on div
>>> contextmenu on document
>>> 不弹出菜单
>>>
>>> 同样Chrome和IE9有相同的结果,Firefox则会因为click事件中的preventDefault行为影响contextmenu事件的触发
>>>
>>> 根据DOM Event Level3(
>>> http://www.w3.org/TR/DOM-Level-3-Events/#event-type-click )中的描述:
>>>
>>>
>>>
>>> The default action of the click event type varies based on the proximal
>>> event target of the event and the value of the MouseEvent.button or
>>> MouseEvent.buttons attributes. Typical default actions of the click event
>>> type are as follows:
>>>
>>> Left click (MouseEvent.button value is 0, MouseEvent.buttons value is 1):
>>>     If the proximal event target has associated activation behavior, the
>>> default action must be to execute that activation behavior (see Activation
>>> triggers and behavior).
>>>     If the proximal event target is focusable, the default action must be
>>> to give that element document focus.
>>>
>>> Right click (MouseEvent.button value is 1, MouseEvent.buttons value is 2):
>>>     The default action must be to provide a context menu of options
>>> related to that proximal event target.
>>>
>>> Middle click (MouseEvent.button value is 2, MouseEvent.buttons value is
>>> 4):
>>>     If the proximal event target has associated activation behavior, the
>>> default action must be to execute that activation behavior in an alternate
>>> fashion (such as opening a link in a new tab or window).
>>>     If the proximal event target has no associated activation behavior,
>>> the default action must be device- and user-defined, but when associated
>>> with a device wheel, is often to activate an alternate scrolling or panning
>>> mode.
>>>
>>> 可以有以下结论:
>>>
>>>
>>> 1. click事件的default action根据按键的不同有不同的行为,并且明确定义了右键(Right
>>> click)时的行为,因此认为鼠标右键应当能触发click事件。在这一点上,Firefox更靠近标准实现,但仅在document上触发一个不捕获不冒泡的事件,行为较为怪异。在关于右键与click事件的关系上,请大家提供更多的资料或讨论。
>>>
>>> 2. 鼠标右键click事件的default
>>> action是“提供contextmenu”,因此在click事件中使用preventDefault,会阻止contextmenu的出现,这一点所有浏览器一致。但是“不提供contextmenu”是否意味着同时“不触发contextmenu”事件,在这点上各浏览器理解不同,Chrome和IE都选择触发contextmenu但不显示菜单,这一点类似HTML标准中由tabindex引起不可聚焦元素变为可聚焦时(
>>> http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#focus )的相关行为(activation
>>> behavior which will fire a xxx event but does
>>> nothing)。但是Firefox选择同时阻止contextmenu事件的触发。在这两者之间哪一个正为准确,邀请大家讨论。
>>>
>>> --------------------------------------------------------
>>>
>>> Gray Zhang
>>> Mail: otakustay@gmail.com
>>> Blog: http://www.otakustay.com
>>> Weibo: http://www.weibo.com/otakustay
>>>
>>
>>

Received on Wednesday, 21 March 2012 05:44:26 UTC