在jQuery UI Tooltip中获取对hovered元素的引用

时间:2013-04-22 03:14:08

标签: javascript jquery jquery-ui firefox jquery-ui-tooltip

基本上,我将open处理程序附加到我的jQuery UI工具提示,该工具提示对触发工具提示的元素执行一些检查。到目前为止我得到了什么:

$(document).tooltip({
  open: function(e, ui) {
    var el = e.toElement/* || e.relatedTarget*/;
    console.log(el.offsetWidth, el.scrollWidth);
    if (el.offsetWidth === el.scrollWidth) {
      ui.tooltip.hide();
    }
  }
});

上面的检查可防止工具提示出现,除非元素水平溢出,这是流体布局的一部分。如您在此jsBin中所看到的,它在Chrome中运行良好。

但是,在Firefox中,event.toElementundefined。从阅读SO周围的线索,我认为event.relatedTarget将是一个合适的替代品,但事实并非如此。虽然event.toElement引用了当前悬停的项目,但event.relatedTarget中的mouseover引用了指针设备退出的元素,这是W3C spec的正确行为(类似于Chrome的event.fromTarget)。

我还尝试了event.targetevent.currentTargetthis引用,但这些引用指向document,因为它是绑定了工具提示事件处理程序的节点。浏览Tooltip API页面也无济于事。

我不确定我是否忽略了一些非常基本的东西,或者我是否应该尝试更少的正统方法。

有没有办法在Firefox中使用工具提示的open处理程序内部触发from的元素?或者是否有一些神奇的jQuery UI Tooltip选项/方法可以更简单/类似的方式实现这种期望的行为?

2 个答案:

答案 0 :(得分:7)

这是一个相当hackish的解决方案,但这是我刚刚发现的临时修复。 编辑:在完成下面的第一个跨浏览器解决方案之后,它根本不是那么hackish。下面列出的#1 #4 #2 解决方案应该可以使用。

jQuery Event对象具有隐藏的originalEvent属性,在问题的情况下,它是对本机mouseover事件的引用。因此,event.originalEvent.target可用于Chrome和Firefox。

open: function(e, ui) {
  var el = e.originalEvent.target;
  if (el.offsetWidth === el.scrollWidth) {
    ui.tooltip.hide();
  }
}

Bin

当涉及旧的IE支持时,如果event.srcElement不存在,则必须使用event.target

var el = e.originalEvent.target || e.originalEvent.srcElement;

Bin


#1跨浏览器解决方案

最后,当触发工具提示的元素中存在嵌套元素时,您必须使用.closest()方法对其进行monkeypatch,并使用与工具提示的委托选择器相同的过滤器(items option ,自UI 1.10.2起默认为[title]:not([disabled])

var el = $(e.originalEvent.target || e.originalEvent.srcElement).closest($(this).tooltip('option', 'items'))[0];

Bin

这基本上是Tooltip Widget内部执行的内容,如here所示。


#2替代跨浏览器解决方案

使用简单的DOM查询不需要这么多解决方法的替代解决方案:

var el = $('[aria-describedby="'+ui.tooltip[0].id+'"]')[0];

Bin


#3滥用内部方法

不应该使用它,但是通过覆盖内部_open方法,您可以访问target jQuery对象,该对象包含作为参数传递给它的事件的目标元素。问题是,然后你甚至没有通过tooltip来访问它的.tooltip('widget')小部件,因为它虽然已经存在于DOM中,但尚未“创建”。您可以使用内部_find方法解决此问题,该方法将执行DOM query by ID,因此您可以在hide动画启动后立即show,同时实时循环不受影响 - 它会像往常一样在mouseleave上移除,但在整个周期中都会display:none

var bk_open = $.ui.tooltip.prototype._open;
$.ui.tooltip.prototype._open = function(event, target, content) {
  bk_open.apply(this, arguments);
  if (target[0].offsetWidth === target[0].scrollWidth) {
    this._find(target).hide();
  }
};

$(document).tooltip();

Bin

使用_find的DOM查询是不必要的,因此我们还可以扩展内部_tooltip方法,该方法返回包含tooltip元素的jQuery对象,以便我们可以使用JS的词法范围来在被覆盖的_open执行之前保存对tooltip元素的引用:

var tooltipproto = $.ui.tooltip.prototype,
    bk_open = tooltipproto._open,
    bk_tooltip = tooltipproto._tooltip,
    $tooltip;
tooltipproto._open = function(event, target, content) {
  bk_open.apply(this, arguments);
  if (target[0].offsetWidth === target[0].scrollWidth) {
    $tooltip.hide();
  }
};
tooltipproto._tooltip = function(element) {
  return ($tooltip = bk_tooltip.apply(this, arguments));
};
$(document).tooltip();

Bin

当然,因为_tooltip内部方法接收target作为参数并返回tooltip,所以可以覆盖此方法执行整个操作,但是{{1}此方法返回后,这是tooltip n,这将需要show可能导致不良的闪烁效应。

这对于一些如此简单的事情来说过于苛刻,笨拙和冗长。


#4清洁解决方案

“清理”,如不使用未记录的方法,也不使用属性,也不使用原型覆盖或DOM查询。回到第一个片段,我们需要的只是对触发工具提示的元素的引用。此元素由setTimeout(fn, 0)函数内部的this引用,该函数在content处理程序之前调用,因此我们可以使用词法范围将该引用存储在上面的级别:

open

Bin

请注意,上面代码段中的自定义var el; $(document).tooltip({ content: function() { el = this; return this.title; }, open: function(e, ui) { if (el.offsetWidth === el.scrollWidth) { ui.tooltip.hide(); } } }); 功能会删除jQuery的default HTML tags stripping(因为我喜欢在工具提示中使用HTML),但如果您动态填充title属性,这可能会出现问题使用用户输入的数据,以防您希望保留原始content处理程序的功能:

content

Bin


我将在jQuery UI bugtracker上打开一张票,要求同时实现此功能。就是这样:

Tooltip: Expose element which triggered the tooltip inside open/close handlers

答案 1 :(得分:2)

仅为了完整性:窗口小部件包含属性tooltips,该对象包含所有打开工具提示的ID作为键,关联的目标元素作为值。

var widget = $(this).data("ui-tooltip");
var el = widget.tooltips[ui.tooltip[0].id][0];

它很干净,因为你直接引用了元素,但也有点脏,因为它是一个可能会改变的实现细节。

那就是说ui.target之类的东西确实很好。