Internet Explorer 编程简述(十一)实现完美的Inplace Drag & Drop——“超级拖放”

关键字:超级拖放,GetDropTarget,ondragover,IHTMLDataTransfer
 
1、概述
许多多窗口浏览器都提供了一种被称为“超级拖放”(或“超级拖拽”、“随心拖放”等等,不一而足)的功能。作为对IE拖拽行为对扩展,“超级拖放”实现了一些非常实用的功能:
  • 拖放网页链接:通常是在新窗口中打开
  • 拖放选中的文字:保存文字、作为关键字通过搜索引擎搜索网络、作为Url打开等
  • 拖放图片:通常是保存图片到指定文件夹
  • 当然,还有很关键的一点:拖动对象时鼠标指针反馈不同的拖拽效果
在《 Internet Explorer 编程简述(十)响应来自HTML Element的事件通知——几个好用的类 》中曾提到,尽管许多浏览器都提供了超级拖放的功能,但与IE的缺省实现相比,除了具备鼠标指针拖拽效果外,还没有哪个浏览器的实现能够实现:
  • 文字在页面内与输入框之间的交互拖放(这一点最为重要)
  • 来自外部的文字与网页输入框之间的交互拖放
  • 拖拽时滚动页面(这一点是被忽略了)
 
本文的目的,一是介绍实现超级拖放的两种方法,二是说明如何实现“完美”的拖放——即扩展IE拖拽行为的同时,保留IE默认的拖拽行为。三是给出一个最为直接和简洁的实现,至于拖放不同的对象以实现不同的功能,不在本文讨论的范围,略去。
 
 
2、标准的实现方法
标准方法即通过IDocHostUIHandler的GetDropTarget成员函数来实现,在MSDN这样说到:
IDocHostUIHandler::GetDropTarget Method——Called by MSHTML when it is used as a drop target. This method enables the host to supply an alternative IDropTarget interface.
即在适当的时候,MSHTML引擎会调用IDocHostUIHandler的GetDropTarget方法,为应用程序提供一个机会来替换MSHTML缺省的DropTarget实现。我们就可以通过这个自定义的DropTarget实现来完成上述的“超级拖放”功能。方法示例如下,其中略去的部分可参考MFC中CHtmlControlSite和CHtmlView的源代码:
 
STDMETHODIMP CHtmlControlSite::XDocHostUIHandler::GetDropTarget(
LPDROPTARGET pDropTarget, LPDROPTARGET* ppDropTarget)
{
METHOD_PROLOGUE_EX_(CHtmlControlSite, DocHostUIHandler)
*ppDropTarget = g_pDropTarget;//将自定义的实现告知MSHTML引擎
return S_OK;
}
 
其中g_pDropTarget指向某个全局的IDropTarget接口的实现,我们假定为CIEDropTarget,CIEDropTarget实现了IDropTarget的几个成员函数DragEnter、DragOver、DragLeave和Drop。在DragEnter中可以决定是否接受一个Drop以及如果接受这个Drop的话该提供怎样的鼠标拖拽反馈,在持续触发的DragOver中同样可以设定鼠标拖拽反馈,从而实现在拖放不同的对象(文字、链接、图像等)时提供不同的拖拽视觉效果,实现相当简单,此处不再赘述。
但上面的实现存在一些问题。首先是选中的文字在页面内与输入框之间交互的拖放没有了。这是自然的,既然我们用自定义的DropTarget替换掉了IE的缺省实现,那这种交互的拖放理应由我们自己实现。难处并非在于不能实现,而是在于实现起来比较麻烦——光是得到鼠标下的HTML Element就够我们烦了;当输入框中有文字的时候,光标还应该随着鼠标的移动而移动——所以这个费力还不一定讨好的功能似乎没有哪个浏览器去做。其次,作为输入框文字拖放的衍生物,拖拽滚动没有了。当鼠标向某个方向拖拽时,网页应该随着将不可见的部分滚动出来,比如某个输入框,让我们有机会将文字拖拽过去。这个Feature的实现并不困难,不过一来是被忽略了(注意到拖拽滚动的人并不多),二来主要Feature都没有实现,这个滚动也意义不大了。
 
3、打入MSHTML内部
既然从GetDropTarget提供外部实现难以得到与输入框的交互式拖放,那就换个角度来考虑问题,让我们打入MSHTML的内部。
着手点是IHTMLDocumentX接口——操纵IE的DOM的法宝。我们注意到IHTMLDocument2有个ondragstart事件,进而想到应该也有诸如ondragenter、ondragover、ondrop之类的事件(事实上也是有的),如果响应这些事件,处理同输入框的交互式拖放应该就能够解决。因为这些拖放在MSHTML的缺省DropTarget实现中发生,因而当鼠标拖拽到某个输入框上时,肯定会触发一个ondragover事件,而在IHTMLEventObj的辅助下我们能轻松得到相关的HTML Element,其它的操作就容易进行了。再细心一点,我们还发现IHTMLEventObj2接口有个dataTransfer属性——可以得到一个IHTMLDataTransfer的指针,而IHTMLDataTransfer接口正是浏览器内部用于数据交换的重要手段之一(看看它的属性就知道会很有用了):
IHTMLDataTransfer Members
clearData——Removes one or more data formats from the clipboard through dataTransfer or clipboardData object.
dropEffect——Sets or retrieves the type of drag-and-drop operation and the type of cursor to display.
effectAllowed——Sets or retrieves, on the source element, which data transfer operations are allowed for the object.
getData——Retrieves the data in the specified format from the clipboard through the dataTransfer or clipboardData objects.
setData——Assigns data in a specified format to the dataTransfer or clipboardData object.
 
更进一步,从IHTMLDataTransfer接口还可以访问到IDataObject接口,在进行Ole拖放时,数据就是通过IDataObject接口来传递的。具体用法稍后讨论。
 
4、打入MSHTML内部——思路
提供鼠标反馈效果与实现GetDropTarget的方法类似,有了IHTMLDataTransfer接口,便可在ondragstart及ondragover事件触发时通过dropEffect属性设置拖拽的效果(可根据需要自行设定,不设置的话使用默认的效果)。再者,“拖”和“放”都在MSHTML的缺省实现中发生,我们从IHTMLEventObj的SrcElement即可得知鼠标所位置的HTML Element是否是输入框。
 
5、打入MSHTML内部——实现
要接收到ondragstart之类的事件,可以采用《 Internet Explorer 编程简述(十)响应来自HTML Element的事件通知——几个好用的类 》中提到的CHtmlObj类和CHtmlElements类,并在适当的地方连接到Document,示例代码如下所示:
 
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值