获取对 jQuery UI 中悬停元素的引用 工具提示

Get reference to hovered element in jQuery UI Tooltip

提问人:Fabrício Matté 提问时间:4/22/2013 最后编辑:Fabrício Matté 更新时间:4/22/2013 访问量:8634

问:

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

$(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 中,是 .通过阅读有关 SO 的帖子,我认为这将是一个合适的替代品,但事实并非如此。在引用当前悬停的项目时,在 a 中引用指针设备退出的元素,这是 W3C 规范的正确行为(类似于 Chrome 的)。event.toElementundefinedevent.relatedTargetevent.toElementevent.relatedTargetmouseoverevent.fromTarget

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

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

有没有办法从工具提示的处理程序内部获取对触发元素的引用,这在Firefox中有效?或者是否有一些神奇的jQuery UI工具提示选项/方法可以以更简单/类似的方式实现这种所需的行为?open

JavaScript jQuery-UI 火狐 jquery-ui-tooltip

评论


答:

7赞 Fabrício Matté 4/22/2013 #1

这是一个相当黑客的解决方案,但这是我刚刚找到的临时修复程序。编辑:在完成下面的第一个跨浏览器解决方案后,它一点也不那么黑客。下面列出的 #1#4#2 解决方案应该是可用的。

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

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

当涉及到旧的IE支持时,当event.target不存在时,你将不得不使用event.srcElement

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


#1 跨浏览器解决方案

最后,当触发工具提示的元素内部有嵌套元素时,您必须使用与工具提示的委托选择器(items 选项,默认为 UI 1.10.2 起)相同的过滤器的 .closest() 方法对其进行猴子修补:[title]:not([disabled])

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

这基本上是工具提示小部件在内部执行的操作,如下所示


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

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

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


#3 内部方法滥用

不应使用此方法,但通过重写内部方法,您可以访问一个 jQuery 对象,该对象包含作为参数传递给它的事件的目标元素。问题是,您甚至无法访问其小部件,因为它虽然已经存在于 DOM 中,但尚未“创建”。您可以使用内部方法解决它,该方法将按 ID 执行 DOM 查询,因此您可以在动画启动后立即使用它,而它的实时周期不受影响 - 它将像往常一样在那里并被删除,但会一直沿用这个周期。_opentargettooltip.tooltip('widget')_findhideshowmouseleavedisplay: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();

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

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();

当然,由于内部方法接收 as 参数并返回 ,因此可以执行整个操作,只是覆盖此方法,但是由于此方法返回后 是 n,因此这可能需要可能导致不良闪烁效果。_tooltiptargettooltiptooltipshowsetTimeout(fn, 0)

不过,对于如此简单的事情来说,这太过笨拙、繁琐和冗长。


#4 清洁溶液

“干净”是指不使用未记录的方法、属性、原型覆盖或 DOM 查询。回到第一个代码片段,我们只需要对触发工具提示的元素进行引用。这个元素是由函数内部引用的,该函数在处理程序之前被调用,因此我们可以使用词法范围将该引用存储在上面的级别:thiscontentopen

var el;
$(document).tooltip({
  content: function() {
    el = this;
    return this.title;
  },
  open: function(e, ui) {
    if (el.offsetWidth === el.scrollWidth) {
      ui.tooltip.hide();
    }
  }
});

请注意,我在上面的代码片段中的自定义函数删除了 jQuery 的默认 HTML 标签剥离(因为我喜欢在工具提示中使用 HTML),但如果您使用用户输入的数据动态填充 title 属性,这可能是一个问题,因此如果您想保留原始处理程序的功能:contentcontent

var el,
    bk_content = $.ui.tooltip.prototype.options.content;
$(document).tooltip({
  content: function() {
    el = this;
    return bk_content.apply(this, arguments);
  },
  open: function(e, ui) {
    if (el.offsetWidth === el.scrollWidth) {
      ui.tooltip.hide();
    }
  }
});


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

工具提示:在打开/关闭处理程序中公开触发工具提示的元素

2赞 a better oliver 4/22/2013 #2

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

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

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

也就是说,这样的东西确实很好。ui.target

评论

0赞 Fabrício Matté 4/22/2013
哦,我知道这个属性,但没能弄清楚部分哈哈。是的,这是一个更干净的解决方案,谢谢。tooltips.data("ui-tooltip")
0赞 Fabrício Matté 4/22/2013
为了提高性能和将来参考,下面是使用 static 方法更新的代码箱:jsbin.com/uxilag/50/edit$.data