【问题标题】:Get reference to hovered element in jQuery UI Tooltip在 jQuery UI 工具提示中获取对悬停元素的引用
【发布时间】:2013-04-22 03:14:07
【问题描述】:

基本上,我将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 引用当前悬停的项目,mouseover 中的 event.relatedTarget 引用指点设备退出的元素,这是根据 W3C spec 的正确行为(类似于 Chrome 的 event.fromTarget)。

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

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

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

【问题讨论】:

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


    【解决方案1】:

    这是一个相当老套的解决方案,但这是我刚刚找到的临时修复。 编辑: 在完成了下面的第一个跨浏览器解决方案之后,它一点也不骇人听闻。下面列出的 #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.target 不存在时,您将不得不使用 event.srcElement

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

    Bin


    #1 跨浏览器解决方案

    最后,当触发工具提示的元素内有嵌套元素时,您必须使用 .closest() 方法对其进行猴子补丁,该方法传递与工具提示的委托选择器相同的过滤器(items option,默认为 @ 987654346@ 从 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('widget') 访问它的tooltip 小部件,因为它虽然已经存在于DOM 中,但尚未“创建”。您可以使用内部的_find 方法解决它,该方法将执行DOM query by ID,因此您可以在show 动画启动后立即hide 它,而它的生命周期不受影响 - 它会在那里并像往常一样在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,所以只需覆盖此方法即可完成整个操作,但tooltipshown 之后此方法返回,这将需要 setTimeout(fn, 0) 可能会导致不良闪烁效果。

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


    #4 清洁解决方案

    “干净”,即不使用未记录的方法、属性、原型覆盖或 DOM 查询。回到第一个 sn-p,我们所需要的只是对触发工具提示的元素的引用。该元素由content 函数内部的this 引用,该函数在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

    请注意,我在上面 sn-p 中的自定义 content 函数删除了 jQuery 的 default HTML tags stripping(因为我喜欢在工具提示中使用 HTML),但是如果您使用用户动态填充标题属性,这可能是一个问题-输入的数据,所以如果你想保留原来的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

    【讨论】:

      【解决方案2】:

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

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

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

      也就是说,ui.target 之类的东西确实不错。

      【讨论】:

      • 哦,我知道tooltips 属性,但未能弄清楚.data("ui-tooltip") 部分哈哈。是的,这是一个更清洁的解决方案,谢谢。
      • 为了性能和未来参考,这里是使用静态 $.data 方法的代码更新后的 bin:jsbin.com/uxilag/50/edit
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-21
      • 1970-01-01
      相关资源
      最近更新 更多