在contenteditable元素中插入链接

我正在开发一个简单的博客系统,我正在使用contenteditable,以便用户可以格式化文本。

到目前为止,一切都像魅力一样。

我想要的下一件事是用户可以在文本中添加超链接。

用户必须选择(部分)文本并单击链接按钮。 之后会打开一个弹出窗口,用户应该输入链接地址。

当用户点击接受按钮时,我想将链接添加到他们在contenteditable中选择的文本。

我怎样才能实现这个function,因为我不知道如何做到这一点?

我的网站:http: //82.170.147.49/blog/3/alpha-release

我网站的jsFiddle: http : //jsfiddle.net/qhN9j/

document.execCommand()在所有主流浏览器中为您执行此操作:

 document.execCommand("CreateLink", false, "http://stackoverflow.com/"); 

要在显示链接对话框时保留选择,可以使用以下function:

 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/

UPDATE

要掌握所创建的链接(如果有的话),这很棘手。 你可以使用我自己的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/

正如alfred所说,已经有很好的编辑器,尤其是基本function。 您可以将其限制为根据需要使用少量或多种function。

从头开始开发它的困难之处在于,所有浏览器的行为都略有不同。 以下应该可以让您在大多数浏览器中朝着正确的方向前进,而不是IE:

 var selected = document.getSelection(); document.execCommand("insertHTML",false,""+selected+""); 

更好看的答案:

 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!  

编辑在Execcommand的IE中是不可能的,因为我们不能在’href’中插入引号,我们必须在带有范围的纯javascript中执行:

//在一个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); 

我会这样做:

  1. 创建一个带有(可能是唯一的)初始伪造href属性的链接来识别它。
  2. 使用document.querySelector('a[href=]')获取该元素。
  3. 您现在可以参考创建的元素,并可以随意使用它。

这样做的好处是您根本不需要使用Selection