基本上,我将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.toElement
为undefined
。从阅读SO周围的线索,我认为event.relatedTarget
将是一个合适的替代品,但事实并非如此。虽然event.toElement
引用了当前悬停的项目,但event.relatedTarget
中的mouseover
引用了指针设备退出的元素,这是W3C spec的正确行为(类似于Chrome的event.fromTarget
)。
我还尝试了event.target
,event.currentTarget
和this
引用,但这些引用指向document
,因为它是绑定了工具提示事件处理程序的节点。浏览Tooltip API页面也无济于事。
我不确定我是否忽略了一些非常基本的东西,或者我是否应该尝试更少的正统方法。
有没有办法在Firefox中使用工具提示的open
处理程序内部触发from的元素?或者是否有一些神奇的jQuery UI Tooltip选项/方法可以更简单/类似的方式实现这种期望的行为?
答案 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();
}
}
当涉及旧的IE支持时,如果event.srcElement
不存在,则必须使用event.target
。
var el = e.originalEvent.target || e.originalEvent.srcElement;
最后,当触发工具提示的元素中存在嵌套元素时,您必须使用.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];
这基本上是Tooltip Widget内部执行的内容,如here所示。
使用简单的DOM查询不需要这么多解决方法的替代解决方案:
var el = $('[aria-describedby="'+ui.tooltip[0].id+'"]')[0];
#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();
使用_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();
当然,因为_tooltip
内部方法接收target
作为参数并返回tooltip
,所以可以覆盖此方法执行整个操作,但是{{1}此方法返回后,这是tooltip
n,这将需要show
可能导致不良的闪烁效应。
这对于一些如此简单的事情来说过于苛刻,笨拙和冗长。
“清理”,如不使用未记录的方法,也不使用属性,也不使用原型覆盖或DOM查询。回到第一个片段,我们需要的只是对触发工具提示的元素的引用。此元素由setTimeout(fn, 0)
函数内部的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();
}
}
});
功能会删除jQuery的default HTML tags stripping(因为我喜欢在工具提示中使用HTML),但如果您动态填充title属性,这可能会出现问题使用用户输入的数据,以防您希望保留原始content
处理程序的功能:
content
我将在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
之类的东西确实很好。