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

标签 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.relatedTargetmouseover引用指针设备退出的元素,这是根据 W3C spec 的正确行为(类似于 Chrome 的 event.fromTarget )。

我也试过 event.target , event.currentTarget this引用,但这些指向 document因为它是绑定(bind)了工具提示事件处理程序的节点。通过Tooltip API页面也没有帮助。

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

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

最佳答案

这是一个相当骇人听闻的解决方案,但这是我刚刚找到的临时修复。 编辑:在完成了下面的第一个跨浏览器解决方案之后,它根本就不那么骇人听闻了。 #1 , #4 #2 下面列出的解决方案应该是可用的。

jQuery 事件对象有一个隐藏的 originalEvent属性,在问题的情况下是引用 native 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() 对其进行猴子补丁。传递与工具提示的委托(delegate)选择器相同的过滤器的方法( items option ,默认为 [title]:not([disabled]) 从 UI 1.10.2 开始):
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 之前保存对工具提示元素的引用执行:
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 ,一个人可以只覆盖这个方法来完成整个操作,但是作为 tooltipshow n 在此方法返回后,这将需要 setTimeout(fn, 0)可能会导致不希望的闪烁效果。

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

#4 清洁解决方案

“干净”,即不使用未记录的方法、属性、原型(prototype)覆盖或 DOM 查询。回到第一个片段,我们所需要的只是对触发工具提示的元素的引用。此元素由 this 引用content 内部在 open 之前调用的函数处理程序,因此我们可以使用词法范围来存储该引用的上一级:
var el;
$(document).tooltip({
  content: function() {
    el = this;
    return this.title;
  },
  open: function(e, ui) {
    if (el.offsetWidth === el.scrollWidth) {
      ui.tooltip.hide();
    }
  }
});

Bin

请注意,我的自定义 content上面代码片段中的函数删除了 jQuery 的 default HTML tags stripping (因为我喜欢在工具提示中使用 HTML),但是如果您使用用户输入的数据动态填充 title 属性,这可能是一个问题,所以如果您想保留原始 content处理程序的功能:
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();
    }
  }
});

Bin

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

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

关于javascript - 在 jQuery UI 工具提示中获取对悬停元素的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16138869/

相关文章:

如果从打开状态单击标签,jQuery 日期选择器将保持打开状态

javascript - 如何内嵌显示网格线元素?

javascript - jquery 仅在我刷新页面以切换 Rails 应用程序时才起作用

javascript - jQuery datepicker - 使用 dateFormat 时默认日期作为选定日期

javascript - 如何将数组拆分为多维数组?

javascript - 在 contenteditable/input 中过滤输入以将插入符号放在原来的位置之后

Javascript:foreach 跳过第一个索引 (0)

javascript - Angular4 - 我需要取消订阅 setTimeout 调用吗?

对于更多 DIV 项目,jQuery 拖放速度会变慢

Jquery 菜单悬停只显示第一个 child