如何从这两个内容相同但结构不同的可编辑div中获得相同的文本?

时间:2019-04-25 07:22:35

标签: javascript html

这是东西:

Contenteditables不好。 Firefox 使用类似div1的东西来处理它,而 Chrome 做类似div2的东西。

两者的文本内容相同(从用户的角度来看),但是它们的结构不同。

当我同时使用innerText获得两个文本内容时,由于它们的结构方式,我会得到不同的结果。

有没有办法获取这些文本并返回相同的字符串(因为它们在屏幕上产生的文本完全相同)?

类似的东西:

div1 = div2 = "Line1\nLine2\n\nLine3\n\n\nLine4"(实际上是div1的结果,因为它仅由文本和中断组成)。在这种情况下,div2是问题。

我需要的伪代码:

“根据屏幕上显示的内容,获取带有中断次数的div的文本内容。”

最终目标:

要在两种结构中始终粘贴新文本,我需要一种以相同方式处理它们的方法。

const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
const p1 = document.getElementById('p1');
const p2 = document.getElementById('p2');

p1.innerText = JSON.stringify(div1.innerText);
p2.innerText = JSON.stringify(div2.innerText);
#div1 {
  border: 1px dotted blue;
}

#div2 {
  margin-top: 40px;
  border: 1px dotted red;
}
<div id="div1" contenteditable>
  Line1
  <br>
  Line2
  <br>
  <br>
  Line3
  <br>
  <br>
  <br>
  Line4
</div>

<p><b>Div1 innerText:</b></p>
<p id="p1"></p>

<div id="div2" contenteditable>
  <div>Line1</div>
  <div>Line2</div>
  <div><br></div>
  <div>Line3</div>
  <div><br></div>
  <div><br></div>
  <div>Line4</div>
</div>

<p><b>Div2 innerText:</b></p>
<p id="p2"></p>

1 个答案:

答案 0 :(得分:1)

我建议您在评论中将<div>的内容转换为<textarea>元素。此解决方案避免了Firefox和Chrome之间的行为差​​异。

下面是一个有关如何实现的简单示例。我想您将能够根据自己的实际需求进行调整(例如将<p>切换为<div>)。

const contentEditable = document.querySelector('#content-editable'),
  htmlPreview = document.querySelector('#html-preview');

htmlPreview.innerText = contentEditable.innerHTML;

contentEditable.addEventListener('click', contentEditableHtmlToTextarea);

/**
 * Converts HTML of #content-editable into <textarea>.
 */
function contentEditableHtmlToTextarea() {
  const textarea = document.createElement('textarea'),
    height = contentEditable.offsetHeight;
  
  // Converts <p> tags to \r\n.
  textarea.value = this.innerHTML
    .replace(/^\s*/gm, '')
    .replace(/<p>(.*?)<\/p>/g, '$1\r\n')
    .trim();
    
  // Updates #content-editable HTML.
  this.innerHTML = '';
  this.appendChild(textarea);
  
  textarea.style.height = `${height}px`;
  htmlPreview.style.display = 'none';
  
  this.removeEventListener('click', contentEditableHtmlToTextarea);
  
  // A bit tricky, but without timeout, the callback is directly called.
  setTimeout(() => {
    document.addEventListener('click', contentEditableTextareaToHtml);
  }, 0);
}

/**
 * Converts <textarea>'s value into HTML for #content-editable.
 */
function contentEditableTextareaToHtml(e) {
  const textarea = contentEditable.querySelector('textarea'),
    // Converts lines into <p> tags.
    html = textarea.value.replace(/^(.+?)$/gm, '<p>$1</p>');
    
  // Checks if the mouse click is outside the <textarea>.
  if (e.target !== textarea) {
    // Updates #content-editable HTML.
    textarea.remove();
    contentEditable.innerHTML = html;
    htmlPreview.innerText = contentEditable.innerHTML;
    
    htmlPreview.style.display = 'block';
    
    document.removeEventListener('click', contentEditableTextareaToHtml);
    contentEditable.addEventListener('click', contentEditableHtmlToTextarea);
  }
}
div {
  padding: 3px;
  
  border: 1px solid #000;
}

textarea {
  margin: 0 auto;
  display: block;

  width: 98%;
}
<div id="content-editable">
  <p>Line 1</p>
  <p>Line 2</p>
  <p>Line 3</p>
</div>

<pre id="html-preview"></pre>