javascript - 如何在生成的 contentEditable div 的顶部和底部附加固定的不可编辑内容?

标签 javascript html css dom contenteditable

我正在尝试在内容可编辑 = true 的动态生成的 div 上“模拟”固定和不可编辑的页眉页脚

首先,我尝试使用此 css 放置页眉和页脚:

.header{
                /*margin:-100px 0px;*/
                margin-left: -2cm;
                background-color: red;
                vertical-align:middle; 
                text-align:center;
            }
            .footer{
                background-color: darkgray;
                margin-top: 735px;
                height: 100px;
                margin-left: -2cm;
            }

并尝试在第一页启用页眉,效果很好:

<div id="editor">
            <div contenteditable="true" class="page" id="page-1">
                <div class="header" contenteditable="false">
                    <img class="brasao" alt="brasao-rj*" src="https://i.imgur.com/ktmBQCS.png" />
                    <span>Procuradoria Geral do Estado do Rio de Janeiro</span>
                </div>
                <b>hello</b>
                <div class="footer" contenteditable="false">
                    Rua Carmo do Cajuru 128
                </div>
            </div>
        </div>

但是页脚没有按预期工作,因为用户可以向下推页脚,将更多内容放在 div 上。

在我目前的方法中,我尝试在调用 newPage.focus() 之前附加“header”div。但不幸的是,行为并不像预期的那样,允许用户同时按下页眉和页脚。

const getHeader = () => {
    let header = document.createElement('div');
    header.setAttribute('contenteditable', false);
    header.setAttribute('class', 'header');
    let imgBrasao = document.createElement('img');
    imgBrasao.class = 'brasao';
    imgBrasao.setAttribute('class', 'brasao');
    imgBrasao.src = 'https://i.imgur.com/ktmBQCS.png';
    let spanPGE = document.createElement('span');
    spanPGE.textContent = 'Procuradoria Geral do Estado do Rio de Janeiro';
    header.appendChild(imgBrasao);
    header.appendChild(spanPGE);
    return header;
};    
const getFooter = () => {
    let footer = document.createElement('div');
    footer.setAttribute('contenteditable', false);
    footer.setAttribute('class', 'footer');
    let spanPGE = document.createElement('span');
    spanPGE.textContent = 'Rua Carmo do Cajuru 128 - Centro RJ';
    footer.appendChild(spanPGE);
    return footer;
};

完整代码在这里:

https://jsitor.com/ETmvUUXaS

(无页眉页脚版本:https://jsitor.com/9J30B6YfG)

那么,我怎样才能在那些内容可编辑的 div 上模拟页眉和页脚呢?

提前致谢!

最佳答案

我设法在没有 jQuery 的情况下做到了。这个概念是在您的内容周围添加一个包装器,并将事件添加到该包装器而不是页面。此外,我创建了一个模板 HTML 页面,这样代码就可以在不执行清理的情况下进行克隆。

为了将页脚放在底部,我将页面显示更改为 flex 并将 flex-direction 更改为 column。然后为页脚设置 margin-top: auto

代码如下:

function redator(divId) {
  const root = document.getElementById(divId)
  const a4 = {
    height: 830,
    width: 595,
    lineHeight: 30
  };
  const template = document.querySelector('#template');
  const headerHeight = root.querySelector('#page-1 .header').offsetHeight;
  const footerHeight = root.querySelector('#page-1 .footer').offsetHeight;

  const getChildrenHeight = (element) => {

    total = parseFloat(getComputedStyle(element).paddingBottom);

    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 getPageHeight = (content) => {
    const children = getChildrenHeight(content);
    return children + headerHeight + footerHeight;

  };

  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 newPage = template.cloneNode(true);
    const pages = root.getElementsByClassName('page');

    newPage.id = 'page-' + (pages.length + 1);
    newPage.className = 'page';
    root.appendChild(newPage);
    newPage.querySelector(".content").focus();
    newPage.querySelector(".content").addEventListener('input', onInput);

    newPage._emptyPage = true;
    return newPage.querySelector(".content");
  };

  function onInput(e) {
    const content = this;
    const page = this.closest(".page")
    const previousPage = page.previousElementSibling;
    const nextPage = page.nextElementSibling;

    const pageHeight = getPageHeight(content);
    const lastChild = content.lastChild;
    const cloneChild = lastChild.cloneNode(true);
    const textContent = content.innerText;
    if ((pageHeight === 0 || textContent.length <= 1) && !!previousPage && !page._emptyPage) {
      page.remove();
      previousPage.querySelector(".content").focus();
      const lastChild = previousPage.querySelector(".content").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.querySelector(".content").insertBefore(cloneChild, nextPage.querySelector(".content").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 .content').addEventListener('input', onInput);
}

document.addEventListener('DOMContentLoaded', function() {
  redator('editor');
}, false);
redator('editor');
#editor {
  background-color: gray;
  border: 1px black;
  padding: 1em 2em;
}

.page {
  background-color: white;
  border: solid black;
  /*padding: 10em 2em;*/
  width: 595px;
  height: 841px;
  display: flex;
  flex-direction: column;
}

.content {
  word-wrap: break-word;
  overflow-wrap: break-word;
  white-space: normal;
  padding-left: 2cm;
  padding-bottom: 2cm;
}

.header {
  background-color: red;
  text-align: center;
}

.footer {
  background-color: darkgray;
  margin-top: auto;
  height: 100px;
}

.brasao {
  height: 60px;
  width: 60px;
}

#template {
  display: none;
}
<h3>My Editor</h3>
<div id="editor">
  <div class="page" id="page-1">
    <div class="header">
      <img class="brasao" alt="brasao-rj*" src="https://i.imgur.com/ktmBQCS.png" />
      <span>Procuradoria Geral do Estado do Rio de Janeiro</span>
    </div>
    <div class='content' contenteditable="true">
      <b>hello</b>
    </div>

    <div class="footer">
      Rua Carmo do Cajuru 128
    </div>
  </div>
</div>


<div id="template">
  <div class="header">
    <img class="brasao" alt="brasao-rj*" src="https://i.imgur.com/ktmBQCS.png" />
    <span>Procuradoria Geral do Estado do Rio de Janeiro</span>
  </div>
  <div class='content' contenteditable="true">

  </div>

  <div class="footer">
    Rua Carmo do Cajuru 128
  </div>
</div>

关于javascript - 如何在生成的 contentEditable div 的顶部和底部附加固定的不可编辑内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58961491/

相关文章:

php - 如何在文本框中显示来自mysql的数据?

javascript - 通过 AJAX 在 HTML 中刷新时间

jQuery 超大不垂直拉伸(stretch)

javascript - 在子页面上也突出显示父菜单

以任意顺序匹配多个可选字符串的 JavaScript 正则表达式

javascript - Sequelizejs : no auto-generation of methods from associations

javascript - 什么阻止了复选框的检查?

javascript - 为容器中的非全宽图像创建视差效果

javascript - 为什么不直接使用 object(map) 来表示邻接表的边呢?如果我们改用数组,我们需要做额外的线性查找操作,不是吗?

javascript - 您可以使用 event.target 定位元素父元素吗?