2011-04-09 107 views
14

我正在研究一個簡單的博客系統,我使用contenteditable,以便用戶可以格式化文本。在contenteditable元素中插入鏈接

到目前爲止,一切都像一個魅力。

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

用戶必須選擇(部分)文本並單擊鏈接按鈕。之後,彈出窗口打開,用戶應該輸入鏈接地址。

當用戶點擊接受按鈕時,我想將鏈接添加到他們在contenteditable中選擇的文本。

我該如何實現這個功能,因爲我不知道如何做到這一點?

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

的jsfiddle:http://jsfiddle.net/qhN9j/

回答

53

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/

UPDATE

要獲得創建鏈接(S)的保持(如果有的話創建在所有)是棘手的。您可以使用我自己的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/

+3

唐先生。你是我所有的英雄!最後,我可以擺脫醜陋的JavaScript提示窗口;)儘管我認爲clmarquart有一個有效的觀點。我想要做的下一件事是創建一個與目標(_blank)的鏈接,我想我需要insertHTML(或其他)爲此。是否有可能通過向'a'標籤添加目標來使代碼工作?如果你能,你不僅是我的英雄,而且我會將你的地位升級爲上帝! :) – PeeHaa 2011-04-12 19:23:37

+2

@PeeHaa:好問題。這將是棘手的,因爲該命令處理多個案例。有時候根本不會創建任何鏈接(如果所選內容已經在具有相同URL的鏈接中)或者只有不在其他鏈接內的內容纔會鏈接。我會補充一點我的答案。 – 2011-04-14 12:02:19

+2

@PeeHaa:更新。 – 2011-04-14 13:53:41

7

阿爾弗雷德表示,已經有發達的編輯,尤其是對基本功能。您可以將其限制爲儘可能少或儘可能多地使用功能。

從零開始開發它的難點在於所有瀏覽器的行爲都略有不同。下面應該讓你在正確的方向在大多數瀏覽器的移動,除了IE:

var selected = document.getSelection(); 
document.execCommand("insertHTML",false,"<a href='"+href+"'>"+selected+"</a>"); 
+0

謝謝clmarquart。適用於大多數瀏覽器。我真的沒有料到它默認會在IE下工作。還有什麼是新的:) – PeeHaa 2011-04-09 15:42:54

+0

現在唯一發生的事情是,當我嘗試輸入一個URL時,選擇不會再被設置在我的文本上。所以我不能添加超鏈接。有沒有辦法在execCommand之前保留/重置選擇? – PeeHaa 2011-04-09 15:55:13

+1

由於您正在使用'

'作爲您的contentEditable區域,因此您使用的是相同的文檔元素,所以發生的情況是當您單擊任何位置時將丟失上一次選擇。嘗試使用「Enter」鍵作爲提交方式,而不是點擊檢查圖標。否則,您可以通過保留範圍來更深入地參考[Mozilla文檔](https://developer.mozilla.org/en/DOM/Selection) – clmarquart 2011-04-09 16:52:33

2

編輯它不可能在IE瀏覽器中的execCommand,因爲我們不能在「HREF」插入引號,我們必須這樣做與純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); 
0

我會做這種方式:

  1. 創建一個(可能是唯一)的鏈接初始虛假href屬性通過識別它。
  2. 使用document.querySelector('a[href=<unique-href>]')獲取該元素。
  3. 您現在可以參考創建的元素,並可以隨心所欲地進行操作。

這樣做的好處是,您根本不需要使用Selection

5

更好看答案:

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來測試,無論如何還有其他方法來檢查它。但是,關鍵部分surroundContents()在IE9中可用,正如MDN所建議的那樣。

最後,我建議使用iFrame而不是contenteditable div,所以不會擔心保留選擇。

+0

這簡單而優雅。它應該是接受的答案。哪裏可以找到所有'.execCommand()'交互的全面列表。他們看起來非常棒,但我對從jQuery轉向猶豫不決。 – 2016-09-27 15:10:45