我正在开发一个简单的博客系统,我正在使用contenteditable,以便用户可以格式化文本。
到目前为止,一切都像魅力一样。
我想要的另一件事是用户可以在文本中添加超链接。
用户必须选择(部分)文本并单击链接按钮。之后会打开一个弹出窗口,用户应该在其中输入链接地址。
当用户点击接受按钮时,我想将链接添加到他们在contenteditable中选择的文本。
如何实现此功能,因为我不知道如何做到这一点?
我的网站:http://82.170.147.49/blog/3/alpha-release
我的网站jsFiddle:http://jsfiddle.net/qhN9j/
答案 0 :(得分:56)
document.execCommand()
在所有主要浏览器中为您提供此功能:
document.execCommand("CreateLink", false, "http://stackoverflow.com/");
要在显示链接对话框时保留选择,您可以使用以下功能:
function saveSelection() {
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
var ranges = [];
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
ranges.push(sel.getRangeAt(i));
}
return ranges;
}
} else if (document.selection && document.selection.createRange) {
return document.selection.createRange();
}
return null;
}
function restoreSelection(savedSel) {
if (savedSel) {
if (window.getSelection) {
sel = window.getSelection();
sel.removeAllRanges();
for (var i = 0, len = savedSel.length; i < len; ++i) {
sel.addRange(savedSel[i]);
}
} else if (document.selection && savedSel.select) {
savedSel.select();
}
}
}
jsFiddle示例:http://jsfiddle.net/JRKwH/1/
<强>更新强>
获取创建的链接(如果有的话),这很棘手。您可以使用我自己的Rangy库:
var sel = rangy.getSelection();
if (sel.rangeCount) {
var links = sel.getRangeAt(0).getNodes([1], function(el) {
return el.nodeName.toLowerCase() == "a";
});
alert(links.length);
}
......或类似以下内容:
function getLinksInSelection() {
var selectedLinks = [];
var range, containerEl, links, linkRange;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
linkRange = document.createRange();
for (var r = 0; r < sel.rangeCount; ++r) {
range = sel.getRangeAt(r);
containerEl = range.commonAncestorContainer;
if (containerEl.nodeType != 1) {
containerEl = containerEl.parentNode;
}
if (containerEl.nodeName.toLowerCase() == "a") {
selectedLinks.push(containerEl);
} else {
links = containerEl.getElementsByTagName("a");
for (var i = 0; i < links.length; ++i) {
linkRange.selectNodeContents(links[i]);
if (linkRange.compareBoundaryPoints(range.END_TO_START, range) < 1 && linkRange.compareBoundaryPoints(range.START_TO_END, range) > -1) {
selectedLinks.push(links[i]);
}
}
}
}
linkRange.detach();
}
} else if (document.selection && document.selection.type != "Control") {
range = document.selection.createRange();
containerEl = range.parentElement();
if (containerEl.nodeName.toLowerCase() == "a") {
selectedLinks.push(containerEl);
} else {
links = containerEl.getElementsByTagName("a");
linkRange = document.body.createTextRange();
for (var i = 0; i < links.length; ++i) {
linkRange.moveToElementText(links[i]);
if (linkRange.compareEndPoints("StartToEnd", range) > -1 && linkRange.compareEndPoints("EndToStart", range) < 1) {
selectedLinks.push(links[i]);
}
}
}
}
return selectedLinks;
}
jsFiddle:http://jsfiddle.net/JRKwH/3/
答案 1 :(得分:7)
正如alfred所说,已经有很好的编辑器,特别是基本功能。您可以将其限制为使用尽可能少的功能或许多功能。
从头开始开发它的困难之处在于,所有浏览器的行为都略有不同。以下应该让您在大多数浏览器中朝着正确的方向前进,而不是IE:
var selected = document.getSelection();
document.execCommand("insertHTML",false,"<a href='"+href+"'>"+selected+"</a>");
答案 2 :(得分:6)
更好看的答案:
function link() {
if (window.getSelection().toString()) {
var a = document.createElement('a');
a.href = 'http://www.google.com';
a.title = 'GOOGLE';
window.getSelection().getRangeAt(0).surroundContents(a);
}
}
select some of text then click link button!
<button onclick='link()'>link text to google</button>
此方法可以在任何地方应用,并且不要求元素为contenteidtable
。
您可以像其他元素一样将任何事件或属性添加到新的A元素。
window.getSelection().toString()
检查是否实际选择了某些文本。它在chrome中工作得很好,我没有IE测试,反正有其他方法可以检查它。但是,正如MDN所建议的那样,IE9中提供了surroundContents()
这个关键部分。
最后我建议使用iFrame而不是contenteditable div,这样就不用担心保留选择。
答案 3 :(得分:2)
编辑在Execcommand的IE中是不可能的,因为我们无法在&#39; href&#39;中插入引号,我们必须在范围内的纯javascript中执行此操作:
// IN DIV IN ONE IFRAME
// Get the frame
var iframe = document.getElementById('myframe');
// Selection object in the frame
theSelection = iframe.contentWindow.getSelection();
// position of the selection to insert
theRange = theSelection.getRangeAt(0);
// get content inside the original selection (and delete content in)
var fragment = theRange.extractContents();
// Create a new link in frame
var newLink = iframe.contentWindow.document.createElement('a');
// Create a text element with the fragment to put in the link
var theText = document.createTextNode(fragment.textContent);
// URL
theLink.href = '#';
// Title
theLink.title = 'title';
// Attribute 'onclick'
theLink.setAttribute('onclick', thelink);
// Target
theLink.target = '_blank';
// Add the text in the link
theLink.appendChild(theText);
// Insert the link at the range
theRange.insertNode(newLink);
//没有框架的DIV
// Selection object in the window
theSelection = window.getSelection();
// begin of the selection to insert
theRange = theSelection.getRangeAt(0);
// get content inside the original selection (and delete content in)
var fragment = theRange.extractContents();
// Create a new link in the document
var newLink = document.createElement('a');
// Create a text element with the fragment to put in the link
var theText = document.createTextNode(fragment.textContent);
// URL
theLink.href = '#';
// Title
theLink.title = 'title';
// Attribute 'onclick'
theLink.setAttribute('onclick', thelink);
// Target
theLink.target = '_blank';
// Add the text in the link
theLink.appendChild(theText);
// Insert the link at the range
theRange.insertNode(newLink);
答案 4 :(得分:0)
我会这样做:
href
属性的链接,以便识别它。document.querySelector('a[href=<unique-href>]')
获取该元素。这样做的好处是您根本不必使用Selection
。