tl;博士
这个想法是允许用户标记任何文本并看到选择旁边的菜单弹出窗口,可能的操作应用于所选文本。
我需要在用户选择的文本旁边放置一个绝对定位按钮。
我正在将mouseup 事件绑定到 Document,并获取选定的文本,但我目前不知道如何知道实际选择的位置,而不将其包装在某个元素中,因为文本的选择可以跨越几个元素,如果我将它包装起来,它会弄乱结构。
这个想法是允许用户标记任何文本并看到选择旁边的菜单弹出窗口,可能的操作应用于所选文本。
我需要在用户选择的文本旁边放置一个绝对定位按钮。
我正在将mouseup 事件绑定到 Document,并获取选定的文本,但我目前不知道如何知道实际选择的位置,而不将其包装在某个元素中,因为文本的选择可以跨越几个元素,如果我将它包装起来,它会弄乱结构。
您可以在选择的末尾放置一个标记跨度,使用 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(win) {
win = win || window;
var doc = win.document;
var sel, range;
// Branch for IE <= 8
if (doc.selection && doc.selection.createRange) {
// Clone the TextRange and collapse
range = doc.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 = doc.getElementById(markerId);
} else if (win.getSelection) {
sel = win.getSelection();
range = sel.getRangeAt(0).cloneRange();
range.collapse(false);
// Create the marker element containing a single invisible character using DOM methods and insert it
markerEl = doc.createElement("span");
markerEl.id = markerId;
markerEl.appendChild( doc.createTextNode(markerTextChar) );
range.insertNode(markerEl);
}
if (markerEl) {
// Lazily create element to be placed next to the selection
if (!selectionEl) {
selectionEl = doc.createElement("div");
selectionEl.style.border = "solid darkblue 1px";
selectionEl.style.backgroundColor = "lightgoldenrodyellow";
selectionEl.innerHTML = "<- selection";
selectionEl.style.position = "absolute";
doc.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);
}
};
})();
当我需要内容不受干扰时,我使用 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
这适用于 Chrome,但 IE 喜欢提供奇怪的东西,所以这是一个跨浏览器的解决方案:(在 Chrome 和 IE 中测试,可能适用于其他地方)
您可能应该在“范围”的末尾插入一个绝对位置元素。这在不同浏览器中的工作方式不同,所以最好的办法可能是嗅探。
既然你问了:这就是纽约时报在他们的“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);
}
}