問題描述
互聯網上有許多所見即所得的編輯器,但我還沒有找到一個實現某種形式的拖放實現.
There are numerous WYSIWYG editors available on the internet, but I'm yet to find one that implements some form of drag-n-drop implementation.
創建自己的編輯器很容易,但我希望用戶能夠從可編輯區域外拖動元素(即標記),并讓他們將其放置在可編輯區域內他們選擇的位置.
It is easy to create one's own editor, but I want to the user to be able to drag elements (ie. tokens) from outside the editable area and have them drop it at a location of their choice inside the editable area.
在可編輯元素的特定位置注入 html 很容易,但是當用戶在可編輯區域中的某個元素上拖動 DIV 時,如何確定插入符號的位置.為了更好地說明我要解釋的內容,請參見以下場景.
It is easy to inject html at a specific location of an editable element, but how do one determine where the caret should be when the user is dragging a DIV over some element in the editable area. To better illustrate what I'm trying to explain, see the following scenario.
可編輯區域(處于編輯模式的 IFRAME 或 contentEditable 屬性設置為 true 的 DIV)已包含以下文本:
The editable area (either an IFRAME in edit mode or a DIV with its contentEditable attribute set to true) already contains the following text:
親愛的,請注意……"
用戶現在從元素列表中將一個表示某個標記的元素拖到可編輯區域上,將光標移動到文本上,直到插入符號出現在文本中的逗號 (,) 之前,如上所示.當用戶在該位置釋放鼠標按鈕時,將注入 HTML,這可能會導致如下結果:
The user now drags an element representing some token from a list of elements, over the editable area, moving the cursor over the text until the caret appear just before the comma (,) in the text as shown above. When the user releases the mouse button at that location, HTML will be injected which could result in something like this:
親愛的 {UserFirstName},請注意……".
"Dear {UserFirstName}, please take note of ...".
我不知道是否有人做過類似的事情,或者至少知道如何使用 JavaScript 來做這件事.
I do not know if anyone has ever done anything similar to this, or at least know of how one would go about doing this using JavaScript.
任何幫助將不勝感激.
推薦答案
這是我解決可編輯元素上的自定義拖動元素問題的方法.最大的問題是當鼠標懸停在可編輯元素上時,無法確定鼠標光標的文本偏移量.我曾嘗試假裝單擊鼠標以將插入符號設置在所需位置,但這不起作用.即使這樣做了,在拖動時也不會直觀地看到插入符號的位置,而只會看到結果拖放.
Here is my approach to solving the issue of custom drag elements on editable elements. The big issue is that one cannot determine the text offset of the mouse cursor when hovering over the editable element. I have tried faking a mouse click to set the caret at the desired position but that did not work. Even if it did, one would not visually see the placement of the caret while dragging, but only the resulting drop.
由于可以將鼠標懸停事件綁定到元素而不是文本節點,因此可以將可編輯元素設置為暫時不可編輯.查找所有元素并將每個文本節點包裝在一個跨度中,以免破壞文本流.每個 span 都應該有一個類名,以便我們可以再次找到它們.
Since one can bind mouse-over events to elements and not text-nodes, one can set the editable element to be temporarily un-editable. Find all elements and wrap each text-node in a span as to not breaking the flow of the text. Each span should be given a classname so we can find them again.
包裝之后,應該再次找到所有包裝的文本節點,并將每個字符與另一個帶有類名的跨度包裝在一起,以便再次找到它們.
After the wrapping, one should again find all the wrapped text-nodes and wrap each character with another span with a classname that one can find them again.
使用事件委托可以向主可編輯元素添加一個事件,該事件將為每個字符范圍應用一種樣式,以顯示插入符號,一個閃爍的 GIF 圖像作為背景.
Using event delegation one can add an event to the main editable element that will apply a style to each character span that will display the caret, a blinking GIF image as a background.
同樣,使用事件委托,應該為每個字符上的鼠標向上事件(放下事件)添加一個事件.現在可以使用字符跨度在其父級(包裝的文本節點)中的位置(偏移量)來確定偏移量.現在可以撤消所有包裝,保留對計算偏移量的引用,并在撤消包裝時保留對適用文本節點的引用.
Again, using event delegation, one should add an event for the mouse-up event (drop event) on each character. One can now determine the offset using the character span's position (offset) within its parent (wrapped text-node). One can now undo all the wrapping, keeping a reference to the calculated offset and while undoing the wrapping keeping a reference to the applicable text-node.
使用范圍 &瀏覽器的選擇對象,現在可以使用計算的偏移量設置選擇到適用的文本節點,并在新設置的選擇(插入符號位置)處注入所需的 HTML,等等!
Using the range & selection objects of the browser, one can now set the selection using the calculated offset to the applicable text-node and inject the required HTML at the newly set selection (caret position), et viola!
下面是一個使用 jQuery 的片段,它將找到文本節點,將它們包裝起來:
Here follows a snippet using jQuery that will find textnodes, wrap them:
editElement.find("*:not(.text-node)").contents().filter(function(){
return this.nodeType != 1;
}).wrap("<span class="text-node"/>");
要查找每個文本節點并包裝每個字符,請使用:
To find each text-node and wrap each character, use:
editElement.find(".text-node").each(function()
{
var textnode = $(this), text = textnode.text(), result = [];
for (var i = 0; i < text.length; i++) result.push(text.substr(i, 1));
textnode.html("<span class="char">"
+ result.join("</span><span class="char">") + "</span>");
});
要撤消包裝:
editElement.find(".text-node").each(function()
{
this.parentNode.replaceChild(document.createTextNode($(this).text()), this);
});
希望這種方法可以幫助那些面臨類似挑戰的人
Hope this approach helps those having similar challenges
這篇關于在 contentEditable 元素上拖放的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!