提问人:Fabrício Matté 提问时间:4/22/2013 最后编辑:Fabrício Matté 更新时间:4/22/2013 访问量:8634
获取对 jQuery UI 中悬停元素的引用 工具提示
Get reference to hovered element in jQuery UI Tooltip
问:
基本上,我将一个处理程序附加到我的 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.toElement
undefined
event.relatedTarget
event.toElement
event.relatedTarget
mouseover
event.fromTarget
我还尝试了 event.target、event.currentTarget
和引用,但这些都指向,因为它是绑定了工具提示事件处理程序的节点。浏览工具提示 API 页面也无济于事。
this
document
我不确定我是否忽略了一些非常基本的东西,或者我是否应该尝试更不正统的方法。
有没有办法从工具提示的处理程序内部获取对触发元素的引用,这在Firefox中有效?或者是否有一些神奇的jQuery UI工具提示选项/方法可以以更简单/类似的方式实现这种所需的行为?open
答:
这是一个相当黑客的解决方案,但这是我刚刚找到的临时修复程序。编辑:在完成下面的第一个跨浏览器解决方案后,它一点也不那么黑客。下面列出的 #1、#4 和 #2 解决方案应该是可用的。
jQuery Event 对象具有一个隐藏属性,在问题的情况下,该属性是引用本机事件。因此,它既可用于Chrome,也可用于Firefox。originalEvent
mouseover
event.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 查询,因此您可以在动画启动后立即使用它,而它的实时周期不受影响 - 它将像往常一样在那里并被删除,但会一直沿用这个周期。_open
target
tooltip
.tooltip('widget')
_find
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();
DOM 查询是相当不必要的,因此我们还可以扩展内部方法,该方法返回包含该元素的 jQuery 对象,以便我们可以在重写执行之前使用 JS 的词法范围来保存对 tooltip 元素的引用:_find
_tooltip
tooltip
_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,因此这可能需要可能导致不良闪烁效果。_tooltip
target
tooltip
tooltip
show
setTimeout(fn, 0)
不过,对于如此简单的事情来说,这太过笨拙、繁琐和冗长。
#4 清洁溶液
“干净”是指不使用未记录的方法、属性、原型覆盖或 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();
}
}
});
请注意,我在上面的代码片段中的自定义函数删除了 jQuery 的默认 HTML 标签剥离(因为我喜欢在工具提示中使用 HTML),但如果您使用用户输入的数据动态填充 title 属性,这可能是一个问题,因此如果您想保留原始处理程序的功能:content
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();
}
}
});
我将在 jQuery UI bugtracker 上打开一张票,要求同时实现此功能。就是这样:
只是为了完整起见:小部件包含属性,该对象包含所有打开的工具提示的 ID 作为键,并将关联的目标元素作为值。tooltips
var widget = $(this).data("ui-tooltip");
var el = widget.tooltips[ui.tooltip[0].id][0];
它很干净,因为你直接引用了元素,但也有点脏,因为它是一个可能会改变的实现细节。
也就是说,这样的东西确实很好。ui.target
评论
tooltips
.data("ui-tooltip")
下一个:选择元素是否具有标准值属性?
评论