Objective
Have a small magnifying glass icon that appears in the top right corner of a table cell when the table cell is hovered over. Mousing over the magnifying glass icon and clicking it will open a dialog window to show detailed information about the item in that particular table cell. I want to reuse the same icon for hundreds of table cells without recreating it each time.
Partial Solution
Have a single <span>
that is absolutely positioned and hidden. When a _previewable
table cell is hovered, the <span>
is moved to the correct location and shown. This <span>
is also moved in the DOM to be a child of the _previewable
table cell. This enables a click handler attached to the <span>
to find the _previewable
parent, and get information from it's jquery data() object that is used to populate the contents of the dialog.
Here is a very simplified version of my HTML:
<body>
<span id="options">
<a class="ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-search"></span>
Preview
</a>
</span>
<table>
<tr>
<td class="_previewable">
<img scr="user_1.png"/>
<span>Bob Smith</span>
</td>
</tr>
</table>
</body>
And this CSS:
#options {
position: absolute;
display: none;
}
With this jQuery code:
var $options = $('#options');
$options.click(function() {
$item = $(this).parents("._previewable");
// Show popup based on data in $item.data("id");
Layout.renderPopup($item.data("id"),$item.data("popup"));
});
$('._previewable').live('mouseover mouseout',function(event) {
if (event.type == 'mouseover') {
var $target = $(this);
var $parent = $target.offsetParent()[0];
var left = $parent.scrollLeft + $target.position().left
+ $target.outerWidth() - $options.outerWid开发者_开发技巧th() + 1;
var top = $parent.scrollTop + $target.position().top + 2;
$options.appendTo($target);
$options.css({
"left": left + "px",
"top": top + "px"
}).show();
}
else {
// On mouseout, $options continues to be a child of $(this)
$options.hide();
}
});
Problem
This solution works perfectly until the contents of my table are reloaded or changed via AJAX. Because the <span>
was moved from the <body>
to be a child of the cell, it gets thrown out and replaced during the AJAX call. So my first thought is to move the <span>
back to the body on mouseout of the table cell, like this:
else {
// On mouseout, $options is moved back to be a child of body
$options.appendTo("body");
$options.hide();
}
However, with this, the <span>
disappears as soon as it is mouseover. The mouseout event seems to be called on _previewable
when the mouse moves into the <span>
, even though the <span>
is a child of _previewable
and fully displayed within the boundaries of the _previewable
table cell. At this point, I've only tested this in Chrome.
Questions
Why would mouseout be called on
_previewable
, when the mouse is still within the boundaries of_previewable
? Is it because the<span>
is absolutely positioned?How can I make this work, without recreating the
<span>
and it's click handler on each AJAX table referesh?
If you change your events then the rest of what you have (appending to <body>
) will work, like this:
$('._previewable').live('mousenter mouseleave',function(event) {
Unlike mouseover
and mouseout
, the mousenter
and mouseleave
events won't fire when moving to or from a child, so they'll behave like you want in this case.
For cleanliness though, I'd bind .live('mouseenter
) and .live('mouseleave')
separately and remove the if()
, it's much easier to look and see what's going on, might be just me though :)
That looks like a whole lot of work just to avoid having the little tiny image in each cell. You're not really gaining very much by "reusing" just one instance of the element. Browsers will only have to download the image once. And from a performance point of view, fiddling with the DOM tree takes more resources than just switching the display property of a highlighted element.
Simplest approach may just be to put the <span>
in every cell you ever print out, then use CSS to hide/display.
精彩评论