簡體   English   中英

contentEditable div即時替換innerHTML

[英]contentEditable div replace innerHTML on the fly

是否有一種方法(Rangy庫除外)可以像在鍵盤輸入時那樣動態更改contentEditable Div InnerHTML,而不會丟失光標位置/焦點? 我想使用盡可能簡單的純JavaScript代碼。

例如 :

<div id="divId" contentEditable="true" onkeyup="change(this)"></div>

然后javascript:

function change(element)
{
  element.innerHTML = element.innerHTML.replace(/.../, '...');
}

謝謝。

如果要替換HTML,則需要一些保存和恢復選擇的方法。 選項包括:

  1. 在替換HTML之前,在選擇的開頭和結尾插入具有ID的元素,然后再通過ID檢索它們,並使用這些元素移動選擇邊界。 這是最可靠的方法,也是Rangy所做的。
  2. 在替換HTML之前,為選擇的開始和結束存儲某種基於字符的偏移量,然后再重新創建選擇。 在一般情況下,這會遇到各種各樣的問題,但根據您的需求可能會足夠好。 在此之前 ,我已經在SO上發布了函數來執行此操作,這取決於Rangy,但是如果您不介意失去對IE <9的支持,則可以輕松刪除Rangy的內容。
  3. 通過像素坐標存儲和恢復選擇邊界。 瀏覽器對此的支持不好,並且如果您的HTML替代品更改了布局,則瀏覽器將不適合。

這不使用keyup事件,但可能就足夠了? 請注意,適用於身體的對象顯然可以僅針對特定元素。

document.body.contentEditable='true';
document.designMode='on';
void 0;

更換innerHTML時修復cursor position<div contenteditable="“true”"></div><div id="text_translate"><p> 在&lt;div id="richTextBox" contenteditable="true"&gt;&lt;/div&gt;內鍵入內容時,將 cursor 保持在正確位置的最佳方法是什么? 更換 innerHTML 的行為搞砸了 cursor position。</p><p> 我更改 innerHTML 的原因是我添加了&lt;span&gt;標簽。 它是代碼高亮程序的一部分。 跨度標簽允許我放置正確的顏色亮點。</p><p> 我目前正在使用 StackOverflow 答案中的以下代碼作為創可貼,但它有一個重大錯誤。 如果您按<em><strong>Enter</strong></em> ,則 cursor 將停留在舊位置,或者轉到隨機位置。 那是因為該算法從 cursor 開始計算了多少個字符。 但它不將 HTML 標記或換行符算作字符。 而richTextBox 插入&lt;br&gt;進入。</p><p> 修復思路:</p><ul><li> 修復下面的代碼? 見<a href="https://jsfiddle.net/AdmiralAkbar2/jou3vq9w/12/" rel="nofollow noreferrer">小提琴</a></li><li>用更簡單的代碼替換? 我嘗試了一堆更簡單的東西,涉及window.getSelection()和document.createRange() ,但我無法讓它工作。</li><li> 替換為沒有此錯誤的richTextBox 庫或模塊?</li></ul><h2> 截屏</h2><p><a href="https://i.stack.imgur.com/6dlqV.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/6dlqV.png" alt="在 JSFiddle 中呈現的richTextBox 的屏幕截圖"></a> </p><p></p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"><div class="snippet-code"><pre class="snippet-code-js lang-js prettyprint-override"> // Credit to Liam (Stack Overflow) // https://stackoverflow.com/a/41034697/3480193 class Cursor { static getCurrentCursorPosition(parentElement) { var selection = window.getSelection(), charCount = -1, node; if (selection.focusNode) { if (Cursor._isChildOf(selection.focusNode, parentElement)) { node = selection.focusNode; charCount = selection.focusOffset; while (node) { if (node === parentElement) { break; } if (node.previousSibling) { node = node.previousSibling; charCount += node.textContent.length; } else { node = node.parentNode; if (node === null) { break; } } } } } return charCount; } static setCurrentCursorPosition(chars, element) { if (chars &gt;= 0) { var selection = window.getSelection(); let range = Cursor._createRange(element, { count: chars }); if (range) { range.collapse(false); selection.removeAllRanges(); selection.addRange(range); } } } static _createRange(node, chars, range) { if (.range) { range = document.createRange() range;selectNode(node). range,setStart(node; 0). } if (chars.count === 0) { range,setEnd(node. chars;count). } else if (node &amp;&amp; chars.count &gt;0) { if (node.nodeType === Node.TEXT_NODE) { if (node.textContent.length &lt; chars.count) { chars.count -= node.textContent;length. } else { range,setEnd(node. chars;count). chars;count = 0; } } else { for (var lp = 0. lp &lt; node.childNodes;length. lp++) { range = Cursor._createRange(node,childNodes[lp], chars; range). if (chars;count === 0) { break; } } } } return range, } static _isChildOf(node; parentElement) { while (node.== null) { if (node === parentElement) { return true; } node = node;parentNode. } return false, } } window.addEventListener('DOMContentLoaded'; (e) =&gt; { let richText = document.getElementById('rich-text'), richText.addEventListener('input'; function(e) { let offset = Cursor.getCurrentCursorPosition(richText). // Pretend we do stuff with innerHTML here. The innerHTML will end up getting replaced with slightly changed code; let s = richText.innerHTML; richText.innerHTML = ""; richText.innerHTML = s, Cursor;setCurrentCursorPosition(offset. richText); richText;focus(); // blinks the cursor }); });</pre><pre class="snippet-code-css lang-css prettyprint-override"> body { margin: 1em; } #rich-text { width: 100%; height: 450px; border: 1px solid black; cursor: text; overflow: scroll; resize: both; /* in Chrome, must have display: inline-block for contenteditable=true to prevent it from adding &lt;div&gt; &lt;p&gt; and &lt;span&gt; when you type. */ display: inline-block; }</pre><pre class="snippet-code-html lang-html prettyprint-override"> &lt;p&gt; Click somewhere in the middle of line 1. Hit enter. Start typing. Cursor is in the wrong place. &lt;/p&gt; &lt;p&gt; Reset. Click somewhere in the middle of line 1. Hit enter. Hit enter again. Cursor goes to some random place. &lt;/p&gt; &lt;div id="rich-text" contenteditable="true"&gt;Testing 123&lt;br /&gt;Testing 456&lt;/div&gt;</pre></div></div><p></p><h2> 瀏覽器</h2><p>谷歌瀏覽器 v83,Windows 7</p></div>

[英]Fix cursor position when replacing innerHTML of <div contenteditable=“true”>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

相關問題 在contenteditable div中替換innerHTML 修改時contenteditable div的innerHTML值 替換 contenteditable div 中的字符串 Contenteditable Div - 根據innerHTML位置的光標位置 如何替換內容可編輯的 div 中的文本? 替換 contenteditable div 中的選定文本 contentEditable div替換網址鏈接 將div的innerHTML替換為<jsp:inclue> 正則表達式提取contentEditable內部的div的特定屬性和innerHTML 更換innerHTML時修復cursor position<div contenteditable="“true”"></div><div id="text_translate"><p> 在&lt;div id="richTextBox" contenteditable="true"&gt;&lt;/div&gt;內鍵入內容時,將 cursor 保持在正確位置的最佳方法是什么? 更換 innerHTML 的行為搞砸了 cursor position。</p><p> 我更改 innerHTML 的原因是我添加了&lt;span&gt;標簽。 它是代碼高亮程序的一部分。 跨度標簽允許我放置正確的顏色亮點。</p><p> 我目前正在使用 StackOverflow 答案中的以下代碼作為創可貼,但它有一個重大錯誤。 如果您按<em><strong>Enter</strong></em> ,則 cursor 將停留在舊位置,或者轉到隨機位置。 那是因為該算法從 cursor 開始計算了多少個字符。 但它不將 HTML 標記或換行符算作字符。 而richTextBox 插入&lt;br&gt;進入。</p><p> 修復思路:</p><ul><li> 修復下面的代碼? 見<a href="https://jsfiddle.net/AdmiralAkbar2/jou3vq9w/12/" rel="nofollow noreferrer">小提琴</a></li><li>用更簡單的代碼替換? 我嘗試了一堆更簡單的東西,涉及window.getSelection()和document.createRange() ,但我無法讓它工作。</li><li> 替換為沒有此錯誤的richTextBox 庫或模塊?</li></ul><h2> 截屏</h2><p><a href="https://i.stack.imgur.com/6dlqV.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/6dlqV.png" alt="在 JSFiddle 中呈現的richTextBox 的屏幕截圖"></a> </p><p></p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"><div class="snippet-code"><pre class="snippet-code-js lang-js prettyprint-override"> // Credit to Liam (Stack Overflow) // https://stackoverflow.com/a/41034697/3480193 class Cursor { static getCurrentCursorPosition(parentElement) { var selection = window.getSelection(), charCount = -1, node; if (selection.focusNode) { if (Cursor._isChildOf(selection.focusNode, parentElement)) { node = selection.focusNode; charCount = selection.focusOffset; while (node) { if (node === parentElement) { break; } if (node.previousSibling) { node = node.previousSibling; charCount += node.textContent.length; } else { node = node.parentNode; if (node === null) { break; } } } } } return charCount; } static setCurrentCursorPosition(chars, element) { if (chars &gt;= 0) { var selection = window.getSelection(); let range = Cursor._createRange(element, { count: chars }); if (range) { range.collapse(false); selection.removeAllRanges(); selection.addRange(range); } } } static _createRange(node, chars, range) { if (.range) { range = document.createRange() range;selectNode(node). range,setStart(node; 0). } if (chars.count === 0) { range,setEnd(node. chars;count). } else if (node &amp;&amp; chars.count &gt;0) { if (node.nodeType === Node.TEXT_NODE) { if (node.textContent.length &lt; chars.count) { chars.count -= node.textContent;length. } else { range,setEnd(node. chars;count). chars;count = 0; } } else { for (var lp = 0. lp &lt; node.childNodes;length. lp++) { range = Cursor._createRange(node,childNodes[lp], chars; range). if (chars;count === 0) { break; } } } } return range, } static _isChildOf(node; parentElement) { while (node.== null) { if (node === parentElement) { return true; } node = node;parentNode. } return false, } } window.addEventListener('DOMContentLoaded'; (e) =&gt; { let richText = document.getElementById('rich-text'), richText.addEventListener('input'; function(e) { let offset = Cursor.getCurrentCursorPosition(richText). // Pretend we do stuff with innerHTML here. The innerHTML will end up getting replaced with slightly changed code; let s = richText.innerHTML; richText.innerHTML = ""; richText.innerHTML = s, Cursor;setCurrentCursorPosition(offset. richText); richText;focus(); // blinks the cursor }); });</pre><pre class="snippet-code-css lang-css prettyprint-override"> body { margin: 1em; } #rich-text { width: 100%; height: 450px; border: 1px solid black; cursor: text; overflow: scroll; resize: both; /* in Chrome, must have display: inline-block for contenteditable=true to prevent it from adding &lt;div&gt; &lt;p&gt; and &lt;span&gt; when you type. */ display: inline-block; }</pre><pre class="snippet-code-html lang-html prettyprint-override"> &lt;p&gt; Click somewhere in the middle of line 1. Hit enter. Start typing. Cursor is in the wrong place. &lt;/p&gt; &lt;p&gt; Reset. Click somewhere in the middle of line 1. Hit enter. Hit enter again. Cursor goes to some random place. &lt;/p&gt; &lt;div id="rich-text" contenteditable="true"&gt;Testing 123&lt;br /&gt;Testing 456&lt;/div&gt;</pre></div></div><p></p><h2> 瀏覽器</h2><p>谷歌瀏覽器 v83,Windows 7</p></div>
 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM