答复: 文字框裡的文字拖曳問題

我从原生webkit windows(对应safari windows版本)介绍浏览器实现的细节。
WebKit对于input element的拖拽处理逻辑是:
假设从input element A拖拽文本data到input element B,从内核事件来说,分别触发了DragEnter、DragOver和Drop,其中重点是Drop事件。
下面分析Drop事件:
1、webkit会判断当前的drag是不是一个move操作,判断的依据是:
	1)、drag source和drag target必须属于相同的document;
	2)、selection是editable;
	3)、selection是range;
	4)、当前是否按下了ctrl键(指Windows平台,也就是说,如果在drag的时候按下了ctrl键,只是copy而不是move)。
2、对于move操作,webkit向input element A、B分别dispatch content change event(不是触发js事件),这就会导致input element A的value被清空,而input element B的value为data;
3、webkit会设置新的selection,同时对input element B设置焦点(focus);
4、对input element B设置焦点之前需要检查old focus node(也就是input element A),如果old focus node的value变化了,需要触发change事件(js事件);webkit使用一个成员变量来保存node最后一次触发chenge事件的value,由于A还未触发过change事件,所以A的这个成员是空的,但是,由于第2步导致A的value被清空了,所以webkit认为A的内容没有发生变化(最后一次change事件保存下来的value和当前A的value都是空),这个就会导致A的onchange事件不会被触发;
5、此时焦点落在B上,并且B的onchange事件也不会被触发;
6、当B失去焦点后,如第4步所说,会检查old focus node(也就是B),因为B从未触发过onchange事件,因此最后一次onchange事件保存下来的value是空,而第2步已经给B的value设置了data。所以触发B的onchange事件。

因此:原生的webkit windows版本对于input element A ---------> input element B
1、A ----> B 不触发A的onchange事件,如果B失去焦点,触发B的onchange事件;
2、B ----> A 触发B的onchange事件,如果A失去焦点,触发A的onchange事件;
3、A ----> B 触发A的onchange事件,如果B失去焦点,触发B的onchange事件。
可见1、3的行为不一致,个人认为这是webkit的bug,因为onchange事件的触发依赖于最后一次触发onchange事件设置的value和当前input element的value。



-----邮件原件-----
发件人: 孙东国 [mailto:sundongguo@gmail.com] 
发送时间: 2012年6月7日 23:23
收件人: Kang-Hao (Kenny) Lu
抄送: W3C HTML5 中文興趣小組
主题: Re: 文字框裡的文字拖曳問題

配合图来把问题说的清楚些,以下情况在 Firefox 12.0 中文版出现。

--------------------图例如下--------------------
输入框:[          ]
文字内容:□□□□□○○○○○(使用两种形状以便区分)
选定的部分:□□■■■○○○○○(后第 3 - 5 个字符被选中)
--------------------------------------------------
假设有两个输入框 A 和 B,他们都监听了 change 事件,A 已经有内容。
A [□□□□□     ]
B [          ]
--------------------------------------------------
选中 A 中的三个字符。
A [□□■■■     ]
B [          ]
--------------------------------------------------
拖拽到 B 中,结果如下。
A [□□■■■     ]
B [□□□       ]
此时焦点仍在 A 中,B 的 change 事件未触发。
--------------------------------------------------
在 B 中再输入两个字符,然后使 B 失去焦点。
A [□□□□□     ]
B [□□□○○     ]
这时 B 会触发 change 事件。
--------------------------------------------------
然后,在 A 中选择中间三个字符。
A [□■■■□     ]
B [□□□○○     ]
--------------------------------------------------
再在 B 中选择最后两个字符。
A [□□□□□     ]
B [□□□●●     ]
注意此时焦点在 B 中,A 看起来没有 selection 了,但实际它还是存在的,稍后可以看到。
--------------------------------------------------
拖拽 B 选中的内容,往 A 里放。
A [□|□□□|□     ]
B [□□□●●     ]
你会发现,光标在刚才的 A 的选区范围内是“Can not drop"状态,也就是说只有在选区的两侧,才可以 drop。
在 A 的内容的最前边 drop。
--------------------------------------------------
结果:
A [○○□□     ]
B [□□□●●     ]
当然,这次 A 的 change 事件也没有被触发。
--------------------------------------------------

IE 系列也有不触发 change 事件的问题,但拖拽行为与 Firefox 不同,问题也没有 Firefox 严重。

Received on Monday, 11 June 2012 07:43:33 UTC