javascript - 动态 contenteditable 脚本在 Firefox 上崩溃(但在 Chrome 上运行)

标签 javascript firefox dom console.log

我正在尝试使用动态克隆 contenteditable div 来模拟多页编辑器。它在 Chrome 上运行非常流畅,但在 Firefox 上,崩溃:

https://jsitor.com/OlL1u2Nim

我什至无法调试在 Firefox 上崩溃的问题。 我该怎么做才能解决这个问题?

提前致谢!

最佳答案

我在 Firefox 上尝试了这个例子,当我到达一个新页面时它崩溃了。这背后的原因是,pages HTMLCollection 在 for 循环中被操作。这类似于 this问题。

作为this建议,如果改为使用向后迭代,则可以避免此问题。然而,最好的解决方案是根本不使用迭代。您可以在创建新页面时动态附加事件监听器,并且可以访问该页面的所有兄弟页面。

此外,在您的示例中,新行在 Chrome 和 Firefox 上的显示方式不同。 Chrome 添加了一个新的 <div>对于每一行,Firefox 使用 <br> .更改 DefaultParagraphSeparatordiv在两个浏览器上产生相同的行。

这个例子适用于两种浏览器:

function redator(divId) {
  const root = document.getElementById(divId)
  const a4 = {
    height: 830,
    width: 595,
    lineHeight: 30
  };
  const getChildrenHeight = (element) => {
    total = 0;
    if (element.childNodes) {
      for (let child of element.childNodes) {
        switch (child.nodeType) {
          case Node.ELEMENT_NODE:
            total += child.offsetHeight;
            break;
          case Node.TEXT_NODE:
            let range = document.createRange();
            range.selectNodeContents(child);
            rect = range.getBoundingClientRect();
            total += (rect.bottom - rect.top);
            break;
        }
      }
    }
    return total;
  };
  const setSelection = (node, offset) =>  {
    let range = document.createRange();
    let sel = window.getSelection();
    range.setStart(node, offset);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
  }
  const addPage = () => {
    const firstPage = root.querySelector('#page-1');
    const newPage = firstPage.cloneNode(true);
    const pages = root.getElementsByClassName('page');
    newPage.addEventListener('input', onInput);
    newPage.innerHTML = '';
    newPage.id = 'page-' + (pages.length + 1);
    firstPage.parentNode.appendChild(newPage);
    newPage.focus();
    newPage._emptyPage = true;
    return newPage;
  }
  function onInput(e) {
    const page = this;
    const previousPage = page.previousElementSibling;
    const nextPage = page.nextElementSibling;
    const pageHeight = getChildrenHeight(page);
    const lastChild = page.lastChild;
    const cloneChild = lastChild.cloneNode(true);
    const textContent = page.innerText;
    if ((pageHeight === 0 || textContent.length <= 1) && !!previousPage && !page._emptyPage) {
      page.remove();
      previousPage.focus();
      const lastChild = previousPage.lastChild;
      setSelection(lastChild, lastChild.childNodes.length);
    } else if (pageHeight > a4.height && !nextPage) {
      lastChild.remove();
      addPage().appendChild(cloneChild);
    } else if (pageHeight > a4.height && nextPage) {
      lastChild.remove();
      nextPage.insertBefore(cloneChild, nextPage.firstChild);
      let selection = getSelection().getRangeAt(0).startContainer.parentElement.closest('div');
      if(selection === page.lastChild) {
        setSelection(cloneChild, 0);
      }
    } else if (pageHeight < a4.height - a4.lineHeight && !!nextPage) {
      let firstChildOfNextPage = nextPage.firstChild;
      let clone = firstChildOfNextPage.cloneNode(true);
      firstChildOfNextPage.remove();
      page.appendChild(clone);
    }
    page._emptyPage = false;
  }

  document.execCommand("DefaultParagraphSeparator", false, "div");
  root.querySelector('#page-1').addEventListener('input', onInput);
}

redator('editor');
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>

<head>
	<title>TODO supply a title</title>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<style>
		#editor {
			background-color: gray;
			border: 1px black;
			padding: 1em 2em;
		}

		.page {
			background-color: white;
			border: solid black;
			padding: 1em 2em;
			width: 595px;
			height: 841px;
			word-wrap: break-word;
			overflow-wrap: break-word;
			white-space: normal;
		}
	</style>
</head>

<body>
	<h3>My Editor</h3>
	<div id="editor">
		<div contenteditable="true" class="page" id="page-1">
			<b>hello</b>
		</div>
	</div>
</body>

</html>

关于javascript - 动态 contenteditable 脚本在 Firefox 上崩溃(但在 Chrome 上运行),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58781106/

相关文章:

javascript - Luxon:如何忽略特定日期的默认时区

php - 使用 getElementById 是否可以实现相同的目的

javascript - For 循环会卡住 Javascript?

html - 隐藏 div 中的表单仍在 Firefox 中显示

jquery - Chrome : trigger click event with jQuery (it works with Firefox)

javascript - GWT 中的 DOM(事件)

javascript - 获取后映射预输入建议

javascript - 将 @supports 与样式组件一起使用

javascript - 更新: Applying AJAX'd JSON data to existing checkboxes and checking/unchecking (jQuery)

javascript - 通过javascript强制firefox在DOM解析中跳过 "text nodes"