我需要在用户所选文本旁边放置一个绝对定位的按钮。就像IE8在内部做的一样。如何在用户文本选择旁边放置元素?
我一个jQuery的鼠标松开事件结合到文档,并获得选定的文本,但我目前不能就如何知道实际的选择定位的思想,没有中某些元素包裹它,因为文本的选择可以跨越多个元素,并且如果我将其包裹,它会混乱结构。
我需要在用户所选文本旁边放置一个绝对定位的按钮。就像IE8在内部做的一样。如何在用户文本选择旁边放置元素?
我一个jQuery的鼠标松开事件结合到文档,并获得选定的文本,但我目前不能就如何知道实际的选择定位的思想,没有中某些元素包裹它,因为文本的选择可以跨越多个元素,并且如果我将其包裹,它会混乱结构。
你可以在选择的结束位置的标记跨度,得到它的坐标使用jQuery,将你的按钮放在这些坐标处并删除标记跨度。
下面应该让你开始:
var markSelection = (function() {
var markerTextChar = "\ufeff";
var markerTextCharEntity = "";
var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2);
var selectionEl;
return function() {
var sel, range;
if (document.selection && document.selection.createRange) {
// Clone the TextRange and collapse
range = document.selection.createRange().duplicate();
range.collapse(false);
// Create the marker element containing a single invisible character by creating literal HTML and insert it
range.pasteHTML('<span id="' + markerId + '" style="position: relative;">' + markerTextCharEntity + '</span>');
markerEl = document.getElementById(markerId);
} else if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt) {
range = sel.getRangeAt(0).cloneRange();
} else {
// Older WebKit doesn't have getRangeAt
range = document.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, sel.focusOffset);
// Handle the case when the selection was selected backwards (from the end to the start in the
// document)
if (range.collapsed !== sel.isCollapsed) {
range.setStart(sel.focusNode, sel.focusOffset);
range.setEnd(sel.anchorNode, sel.anchorOffset);
}
}
range.collapse(false);
// Create the marker element containing a single invisible character using DOM methods and insert it
markerEl = document.createElement("span");
markerEl.id = markerId;
markerEl.appendChild(document.createTextNode(markerTextChar));
range.insertNode(markerEl);
}
if (markerEl) {
// Lazily create element to be placed next to the selection
if (!selectionEl) {
selectionEl = document.createElement("div");
selectionEl.style.border = "solid darkblue 1px";
selectionEl.style.backgroundColor = "lightgoldenrodyellow";
selectionEl.innerHTML = "<- selection";
selectionEl.style.position = "absolute";
document.body.appendChild(selectionEl);
}
// Find markerEl position http://www.quirksmode.org/js/findpos.html
var obj = markerEl;
var left = 0, top = 0;
do {
left += obj.offsetLeft;
top += obj.offsetTop;
} while (obj = obj.offsetParent);
// Move the button into place.
// Substitute your jQuery stuff in here
selectionEl.style.left = left + "px";
selectionEl.style.top = top + "px";
markerEl.parentNode.removeChild(markerEl);
}
};
})();
当我执行这段代码时,top变量是一个对象。可能有一个叫做top的全局变量。最好写var var = 0; var top = 0;而不是var left = top = 0; – 2013-06-19 18:31:54
@ Z-CORE:你绝对正确:'top'是对包含当前文档的最外层窗口的引用。对于我来说,复制和粘贴别人的代码是非常不寻常的(在这种情况下,来自quirksmode.org),但至少很明显,错误并不是我的原因:) – 2013-06-19 23:00:56
虽然不太可能,但可能存在的CSS规则依赖于某些像'#example> span + span'这样的元素顺序。将标记跨度插入内容会破坏那些可能改变/破坏布局的规则。 range.getBoundingClientRect()可能是更健壮的解决方案。 – Rick 2015-06-08 19:25:45
您应该在“范围”末尾插入绝对位置元素。这在不同的浏览器中有不同的作用,所以你最好的选择可能是嗅探。
既然你问:这是纽约时报是如何做的在他们的“altClickToSearch.js”文件:
function insertButton() {
selectionButton = new Element(
'span', {
'className':'nytd_selection_button',
'id':'nytd_selection_button',
'title':'Lookup Word',
'style': 'margin:-20px 0 0 -20px; position:absolute; background:url(http://graphics8.nytimes.com/images/global/word_reference/ref_bubble.png);width:25px;height:29px;cursor:pointer;_background-image: none;filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://graphics8.nytimes.com/images/global/word_reference/ref_bubble.png", sizingMethod="image");'
}
)
if (Prototype.Browser.IE) {
var tmp = new Element('div');
tmp.appendChild(selectionButton);
newRange = selection.duplicate();
newRange.setEndPoint("StartToEnd", selection);
newRange.pasteHTML(tmp.innerHTML);
selectionButton = $('nytd_selection_button');
}
else {
var range = selection.getRangeAt(0);
newRange = document.createRange();
newRange.setStart(selection.focusNode, range.endOffset);
newRange.insertNode(selectionButton);
}
}
谢谢,是的,他们似乎只是在选择中的特定点插入它,而不是绝对的文档本身。谢谢! – vsync 2009-10-19 18:20:06
那里有一个不必要的浏览器嗅探。你可以检查你需要的对象/方法。另外,旧版WebKits中的选择对象(Safari 2,也许3,我对此有点朦胧,而且我没有轻松掌握所有相关的浏览器)没有'getRangeAt'方法。 – 2009-10-19 20:18:53
我并不是建议上面的代码作为最佳解决方案,尤其是浏览器嗅探。他在他的评论中多次问到。这只是该网站的代码。 – 2011-03-16 20:18:16
我用getBoundingClientRect()时,我需要的内容,以保持不受干扰,同时将更多的内容在它附近。
var r=window.getSelection().getRangeAt(0).getBoundingClientRect();
var relative=document.body.parentNode.getBoundingClientRect();
ele.style.top =(r.bottom -relative.top)+'px';//this will place ele below the selection
ele.style.right=-(r.right-relative.right)+'px';//this will align the right edges together
这部作品在浏览器,但IE喜欢给奇怪的事情,所以这里是一个跨浏览器的解决方案:(经测试,在Chrome和IE,可能工作在其他地方)
的HTTP: //www.nytimes.com在他们的文章中做到这一点 – vsync 2009-10-19 16:34:27