【问题标题】:Continue text into separate <p> paragraphs dynamically?将文本动态地分成单独的 <p> 段落?
【发布时间】:2016-03-23 21:30:03
【问题描述】:

以下fiddle 允许将文本粘贴到&lt;textarea&gt; 并动态生成相等的段落&lt;p&gt;,由相同数量的字符组成。


发生的问题是;先前动态生成的段落&lt;p&gt; 中的文本在每个标记内溢出,并且不能正确地继续到下一个动态段落。因此,用户是否可以按下回车键并将该内容向下移动到下一个现有段落,同时仍然动态自动保持现有格式?

如果可以提供一个新的Fiddle,我们将不胜感激,因为我还是新手。再一次,小提琴可以找到here

更新: 是否可以在生成段落后,让用户按下回车键,如果可能的话,将其内容无缝地向下移动到下面的段落中?并且在按下退格按钮时也适用相同的内容,以便内容向上移动到上一段?出现的问题是,当按回车键时,由于 css 中的溢出属性,文本似乎隐藏了文本。


$(function() {
    $("#Go").on('click', function() {
        var theText = $('textarea').val();
        var numberOfCharacters = 300;
        while (theText.length) {
            while (theText.length > numberOfCharacters &&
                theText.charAt(numberOfCharacters) !== ' ') {
                numberOfCharacters++;
            }
            $("#text_land").append("<br><\/br><p>" + theText.substring(
                    0, numberOfCharacters) +
                "<\/p><br><\/br>");
            theText = theText.substring(numberOfCharacters);
            numberOfCharacters = 300;
            $('p').attr('contenteditable', 'true');
            $("p").addClass("text");
        }
    })
})
$('select').on('change', function() {
    var targets = $('#text_land p'),
        property = this.dataset.property;
    targets.css(property, this.value);
}).prop('selectedIndex', 0);
(end);
@media print {
    p {
        page-break-inside: avoid;
    }
}

p {
    position: relative;
}

@media print {
    .no-print,.no-print * {
        display: none !important;
    }
}

p {
    border-style: solid;
    color: #000;
    display: block;
    text-align: justify;
    border-width: 5px;
    font-size: 19px;
    overflow: hidden;
    height: 300px;
    width: 460px;
    word-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


 <div align="center">
        <h4 align="center"><u>Paste text in the field below to divide text into
        paragraphs.</u></h4><br>
        <br>
        <textarea placeholder="Type text here, then press the button below." cols="50" id="textarea1" rows="10">
</textarea><br>
        <br>
        <button id="Go">Divide Text into Paragraphs!</button>
    </div>
    <hr>
    <h2 align="center">Divided Text Will Appear Below:</h2>
    <div>
        <div align="center" id="text_land" style="font-family: monospace">
        </div>
    </div>

【问题讨论】:

  • 你真的需要新的段落标签来包裹每一块文本,还是你需要在文本中的段落之间有先前空格的地方出现空格?
  • 你真的自己尝试过吗?
  • @Joshua - 每个段落都是为每个文本块动态创建的。然而,当文本块被填满时,用户可能需要编辑文本,并且可能希望将文本从上一段移动到新段落,以使文本继续流入下一段。
  • @enguerranws - 是的,我已经尝试解决这个问题,但是如果用户需要编辑生成的段落,我很难解决这个文本流动问题。
  • 那么,您可以粘贴您目前尝试过的内容吗?

标签: javascript jquery html css


【解决方案1】:

用户可以按下回车键并将该内容向下移动到 下一个现有段落,同时仍保留现有的 动态自动格式化

如果我理解正确的话,你想要的是一旦文本被分成段落,然后用户在其中一个中添加一些文本并按 Enter,那么剩余的文本应该流动在接下来的段落中,将溢出的文本与之前一样分配。

类似地,当用户在段落的开头按下 BackSpace 时,文本会再次回到上一段,溢出的文本会像之前一样均匀地分布到其他段落中。

作为一种算法,你需要的是这样的:

  1. 将初始文本分成相等的块并分配到段落中,根据需要动态创建ps。
  2. 在那些 p 元素上收听 keyup 事件
  3. 如果按下的键是Enter
    • 3.1 从按下 Enter 的位置提取剩余文本
    • 3.2 从接下来的所有段落中提取文本,在前面提取的溢出文本前面
    • 3.3 删除接下来的所有段落并像我们在步骤 1 中所做的那样分发组合文本
  4. 如果按下的键是BackSpace
    • 4.1 检查是否在段首,是否有前段
    • 4.2 提取段落文本并附加到下一个所有段落的文本中
    • 4.3 删除接下来的所有段落,包括当前段落,并将提取的文本附加到前一段。
    • 4.4 分发组合文本,就像我们在步骤 1 中所做的那样

有了这个粗略的算法,你就可以开始编码了,看起来像这样:

注 1:这都是 JavaScript,没有 jQuery。
注 2:这过于简化了,您需要进一步优化并解决所有边缘情况。

缓存所需元素并绑定事件处理程序:

var btn = document.getElementById('go'), 
    textarea = document.getElementById('textarea1'), 
    content = document.getElementById('content');

btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);

textarea 分发初始文本,删除现有段落(如果有):

function initialDistribute() {
    var text = textarea.value;
    while (content.hasChildNodes()) { content.removeChild(content.lastChild); }
    rearrange(text);
}

通过动态创建所需数量的段落来重新排列/分配文本的逻辑:

function rearrange(text) {
    var chunks = text.match(/.{1,100}/g) || [];
    chunks.forEach(function(str, idx) {
        para = document.createElement('P');
        para.setAttribute('contenteditable', true);
        para.textContent = str;
        content.appendChild(para);
    });
}

注意 3:我在这个例子中使用了 100 个字符来分割文本。此外,这不会处理空格,并且会在两者之间拆分单词。您将需要在您的代码中执行此操作。 (#见下面的编辑)

用于捕获 Enter (keycode 13) 和 BackSpace (keycode 8) 键的事件处理程序。另外,查看元素是否为p 元素:

function handleKey(e) {
    var para = e.target, position, 
        key, fragment, overflow, remainingText;
    key = e.which || e.keyCode || 0;
    if (para.tagName != 'P') { return; }
    if (key != 13 && key != 8) { return; }
    ...

获取光标位置,判断段落开头是否按下了BackSpace

position = window.getSelection().getRangeAt(0).startOffset;    

如果按下 Enter,则在当前段落的最后一个子段落之后提取文本(当按下 Enter 时,contenteditable 将生成 div),删除该节点,在此之后的所有段落的剩余文本前面加上剩余的段落。

if (key == 13) {
    fragment = para.lastChild; overflow = fragment.textContent;
    fragment.parentNode.removeChild(fragment); 
    remainingText = overflow + removeSiblings(para, false);
    rearrange(remainingText);
}

如果按下了BackSpace,检查是否有前一段以及光标是否在开头。如果是,则从所有后续段落(包括当前段落)中提取剩余文本,同时删除它们:

if (key == 8 && para.previousElementSibling && position == 0) {
    fragment = para.previousElementSibling;
    remainingText = removeSiblings(fragment, true);
    rearrange(remainingText);
}

从后续段落中提取文本并将其删除的逻辑:

function removeSiblings(elem, includeCurrent) {
    var text = '', next;
    if (includeCurrent && !elem.previousElementSibling) { 
        parent = elem.parentNode; text = parent.textContent;
        while (parent.hasChildNodes()) { parent.removeChild(parent.lastChild); }
    } else {
        elem = includeCurrent ? elem.previousElementSibling : elem;
        while (next = elem.nextSibling) { 
            text += next.textContent; elem.parentNode.removeChild(next);
        }
    }
    return text;
}

总而言之,这是一个有效的 sn-p:

片段:

var btn = document.getElementById('go'), 
	textarea = document.getElementById('textarea1'), 
	content = document.getElementById('content'), 
    chunkSize = 100;
    
btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);

function initialDistribute() {
    var text = textarea.value;
    while (content.hasChildNodes()) {
        content.removeChild(content.lastChild);
    }
    rearrange(text);
}

function rearrange(text) {
    var	chunks = splitText(text, false);
    chunks.forEach(function(str, idx) {
        para = document.createElement('P');
        para.setAttribute('contenteditable', true);
        para.textContent = str;
        content.appendChild(para);
    });
}

function handleKey(e) {
    var para = e.target, position, 
        key, fragment, overflow, remainingText;
    key = e.which || e.keyCode || 0;
    if (para.tagName != 'P') { return; }
    if (key != 13 && key != 8) { return; }
		position = window.getSelection().getRangeAt(0).startOffset;    
    if (key == 13) {
        fragment = para.lastChild;
        overflow = fragment.textContent;
        fragment.parentNode.removeChild(fragment); 
        remainingText = overflow + removeSiblings(para, false);
        rearrange(remainingText);
    }
    if (key == 8 && para.previousElementSibling && position == 0) {
        fragment = para.previousElementSibling;
        remainingText = removeSiblings(fragment, true);
        rearrange(remainingText);
    }
}

function removeSiblings(elem, includeCurrent) {
    var text = '', next;
    if (includeCurrent && !elem.previousElementSibling) { 
        parent = elem.parentNode; 
		text = parent.textContent;
        while (parent.hasChildNodes()) {
            parent.removeChild(parent.lastChild);
        }
    } else {
        elem = includeCurrent ? elem.previousElementSibling : elem;
        while (next = elem.nextSibling) { 
            text += next.textContent;
            elem.parentNode.removeChild(next);
        }
    }
    return text;
}

function splitText(text, useRegex) {
	var chunks = [], i, textSize, boundary = 0;
    if (useRegex) { 
        var regex = new RegExp('.{1,' + chunkSize + '}\\b', 'g');
        chunks = text.match(regex) || [];
    } else {
		for (i = 0, textSize = text.length; i < textSize; i = boundary) {
			boundary = i + chunkSize;
			if (boundary <= textSize && text.charAt(boundary) == ' ') {
				chunks.push(text.substring(i, boundary));
			} else {
				while (boundary <= textSize && text.charAt(boundary) != ' ') { boundary++; }
				chunks.push(text.substring(i, boundary));
			}
		}
	}
	return chunks;
}
* { box-sizing: border-box; padding: 0; margin: 0; }
body { font-family: monospace; font-size: 1em; }
h3 { margin: 1.2em 0; }
div { margin: 1.2em; }
textarea { width: 100%; }
button { padding: 0.5em; }
p { padding: 1.2em 0.5em; margin: 1.4em 0; border: 1px dashed #aaa; }
<div>
  <h3>Paste text in the field below to divide text into
        paragraphs..</h3>
  <textarea placeholder="Type text here, then press the button below." id="textarea1" rows="5" ></textarea><br/><br/>
  <button id="go">Divide Text into Paragraphs</button>
</div>
<hr>
<div>
  <h3>Divided Text Will Appear Below:</h3>
  <div id="content"></div>
</div>

还有一个小提琴供你玩:

小提琴:https://jsfiddle.net/abhitalks/jwnnn5oy/


编辑 1:

修复了在单词边界处中断的正则表达式。还添加了相同的非正则表达式程序代码(在 Op 的原始代码行),以演示 Op 如何将他的其他代码段考虑在内并将其集成到其中。

注4:关于Op关于使用jQuery的评论,与手头的问题无关。 jQuery 只不过是 JavaScript,对于他们来说,将 sn-p 片段合并到更大的代码库中应该是微不足道的。

变更集:新增功能splitText


编辑 2:

根据您的评论,如果您希望在用户键入时自动进行重新分配...那么您将需要计算该段落中文本的长度并查看是否超出了您的块大小。如果是这样,则从该段落开始重新分发。对退格执行相反的操作。

我最初发布了解决方案,以满足您的要求,即当用户在任何文本之间按 Enter 键以中断并将其分发到后续段落时。我不建议在用户键入时自动执行此操作,因为更改对用户来说太刺耳了。

片段 2:

var btn = document.getElementById('go'), 
	textarea = document.getElementById('textarea1'), 
	content = document.getElementById('content'), 
    chunkSize = 100;
    
btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);

function initialDistribute() {
    var text = textarea.value;
    while (content.hasChildNodes()) {
        content.removeChild(content.lastChild);
    }
    rearrange(text);
}

function rearrange(text) {
    var	chunks = splitText(text, false);
    chunks.forEach(function(str, idx) {
        para = document.createElement('P');
        para.setAttribute('contenteditable', true);
        para.textContent = str;
        content.appendChild(para);
    });
}

function handleKey(e) {
    var para = e.target, position, 
        key, fragment, overflow, remainingText;
    key = e.which || e.keyCode || 0;
    if (para.tagName != 'P') { return; }
    if (key != 13 && key != 8) { redistributeAuto(para); return; }
		position = window.getSelection().getRangeAt(0).startOffset;    
    if (key == 13) {
        fragment = para.lastChild;
        overflow = fragment.textContent;
        fragment.parentNode.removeChild(fragment); 
        remainingText = overflow + removeSiblings(para, false);
        rearrange(remainingText);
    }
    if (key == 8 && para.previousElementSibling && position == 0) {
        fragment = para.previousElementSibling;
        remainingText = removeSiblings(fragment, true);
        rearrange(remainingText);
    }
}

function redistributeAuto(para) {
	var text = para.textContent, fullText;
	if (text.length > chunkSize) {
		fullText = removeSiblings(para, true);
	}
	rearrange(fullText);
}

function removeSiblings(elem, includeCurrent) {
    var text = '', next;
    if (includeCurrent && !elem.previousElementSibling) { 
        parent = elem.parentNode; 
		text = parent.textContent;
        while (parent.hasChildNodes()) {
            parent.removeChild(parent.lastChild);
        }
    } else {
        elem = includeCurrent ? elem.previousElementSibling : elem;
        while (next = elem.nextSibling) { 
            text += next.textContent;
            elem.parentNode.removeChild(next);
        }
    }
    return text;
}

function splitText(text, useRegex) {
	var chunks = [], i, textSize, boundary = 0;
    if (useRegex) { 
        var regex = new RegExp('.{1,' + chunkSize + '}\\b', 'g');
        chunks = text.match(regex) || [];
    } else {
		for (i = 0, textSize = text.length; i < textSize; i = boundary) {
			boundary = i + chunkSize;
			if (boundary <= textSize && text.charAt(boundary) == ' ') {
				chunks.push(text.substring(i, boundary));
			} else {
				while (boundary <= textSize && text.charAt(boundary) != ' ') { boundary++; }
				chunks.push(text.substring(i, boundary));
			}
		}
	}
	return chunks;
}
* { box-sizing: border-box; padding: 0; margin: 0; }
body { font-family: monospace; font-size: 1em; }
h3 { margin: 1.2em 0; }
div { margin: 1.2em; }
textarea { width: 100%; }
button { padding: 0.5em; }
p { padding: 1.2em 0.5em; margin: 1.4em 0; border: 1px dashed #aaa; }
<div>
  <h3>Paste text in the field below to divide text into
        paragraphs..</h3>
  <textarea placeholder="Type text here, then press the button below." id="textarea1" rows="5" ></textarea><br/><br/>
  <button id="go">Divide Text into Paragraphs</button>
</div>
<hr>
<div>
  <h3>Divided Text Will Appear Below:</h3>
  <div id="content"></div>
</div>

小提琴 2:https://jsfiddle.net/abhitalks/hvhr4ds8/

注意 5:在小提琴中,首先按 Enter 键以中断一些文本,这样您就可以在键入时看到重新分配是如何发生的.另外请注意,由于不分词的逻辑,需要多出几个字符才能重新分配。

变更集:新增功能redistributeAuto

【讨论】:

  • 我已经设法使用

    标签的 css 中的边距设置在每个段落之间添加一个空格,并且还通读了上面的信息。但是,我很难解决缺少单词中的字符的问题。另外,我尝试将原始代码中的 JQuery 结合起来,但无法解决此问题。是否有可能解决此问题,因为我尝试实施解决方案没有成功并且对编码仍然陌生?谢谢。 jsfiddle.net/InnovativeDave/jwnnn5oy/4

  • @Dave:太好了。欣赏你的努力。关于合并分词,大约 12 小时左右后我将能够查看它(在这个世界的这个地区已经接近午夜)。 jQuery 应该不是问题,因为它是 JavaScript。
  • @Dave:那里。我已经编辑了解决断字的答案。
  • 但是,还有一个问题需要解决。由于文本在每个段落中填充,当用户通过 contenteditable="true" 添加更多文本时,它会溢出而不流入下一个段落并隐藏在每个分割的部分下。是否可以使用 maxlength 属性或类似元素来解决此问题?
  • @Dave: maxlength 不起作用,因为它会限制字符数,但您不希望单词中断。此外,文本的分发会产生意想不到的结果。我在答案中添加了另一个编辑。基本上,如果文本长度超过块大小,您可以在每次按键时调用重新分发代码。
【解决方案2】:

非常简单,如果我理解正确的话。

$(function() {
    $("#Go").on('click', function() {
        var theText = $('textarea').val();
        var paragraphs = theText.split('\n\n');
        $("#text_land").html('');
        paragraphs.forEach(function(paragraph) {
          var lines = paragraph.split('\n');
          $('<p class="text" contenteditable />').html(lines.join('<br>')).appendTo("#text_land");
        });
    })
})
$('select').on('change', function() {
    var targets = $('#text_land p'),
        property = this.dataset.property;
    targets.css(property, this.value);
}).prop('selectedIndex', 0);
(end);
@media print {
    p {
        page-break-inside: avoid;
    }
}

p {
    position: relative;
}

@media print {
    .no-print,.no-print * {
        display: none !important;
    }
}

p {
    border-style: solid;
    color: #000;
    display: block;
    text-align: justify;
    border-width: 5px;
    font-size: 19px;
    overflow: hidden;
    height: 300px;
    width: 460px;
    word-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


 <div align="center">
        <h4 align="center"><u>Paste text in the field below to divide text into
        paragraphs.</u></h4><br>
        <br>
        <textarea placeholder="Type text here, then press the button below." cols="50" id="textarea1" rows="10">
</textarea><br>
        <br>
        <button id="Go">Divide Text into Paragraphs!</button>
    </div>
    <hr>
    <h2 align="center">Divided Text Will Appear Below:</h2>
    <div>
        <div align="center" id="text_land" style="font-family: monospace">
        </div>
    </div>

【讨论】:

  • 但是,目标是如果前一个框中的文本溢出,用户可以按 Enter 将该内容向下移动到新框中。如果用户按下退格按钮来恢复他们的更改,这也适用。
  • 您的意思是在&lt;p&gt; 标签内,而不是&lt;textarea&gt;
  • 是的,在

    标签内。

【解决方案3】:

D3 实际上非常适合这种情况。如果我理解正确,&lt;p&gt; 元素的添加和删除应该在编辑时自然出现和消失。

这有点粗糙,但在下面的示例中,在插入两个新行后“检测到”了一个新段落。 &lt;textarea&gt; 值是 .split() 与该标准相对应,并应用于右侧的 &lt;div&gt;,因为它是 data() 数组。因此,对于数据中的每个元素,我们只需输入/退出/更新&lt;p&gt; 元素。当我们编辑文本时,我们可以轻松地添加和删除,而不会出现大量 DOM 抖动。

通过一些修改,您可能可以将&lt;textarea&gt;&lt;p&gt; 合并到某种“所见即所得”的编辑器中...

var text = '';
var break_char = '\n\n';
var editor = d3.select('.editor');
var output = d3.select('.output');

function input_handler () {

  text = editor.node().value;

  var paragraphs = output.selectAll('.paragraph')
    .data(text.split(break_char));

  paragraphs.enter()
    .append('p')
    .attr('class', 'paragraph')
    .style('opacity', 0);

  paragraphs.exit().remove();

  paragraphs
    .text(function (d) { return d })
    .transition()
    .duration(300)
    .style('opacity', 1);
}

editor.on('input', input_handler);
body {
  vertical-align: top;
  height: 100%;
  background-color: #eee;
}
body * {
  box-sizing: border-box;
  font-family: arial;
  font-size: 0.8rem;
  margin: 0.5rem;
  padding: 0.5rem;
}
.input,
.output {
  display: inline-block;
  position: absolute;
  top: 0;
  height: auto;
}
.input {
  left: 0;
  right: 50%;
}
.output {
  left: 50%;
  right: 0;
}
.editor {
  display: inline-block;
  border: 0;
  width: 100%;
  min-height: 10rem;
  height: 100%;
}
.paragraph {
  background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div>
  <div class='input'>
    <textarea class='editor' placeholder='write away...'></textarea>
  </div>
  <div class='output'></div>
</div>

【讨论】:

  • 感谢使用 D3 更新代码。但是,此版本不会在 300 个字符限制之后拆分段落,并且在 textarea 中键入文本时,文本最终会超出空白段落空间,并且不会在每个段落的下方继续。这些问题能解决吗?
  • 在我继续之前,我想要您的测试数据或您输入的任何内容,以便我可以准确生成您所看到的结果。您能否还提供一些背景信息,以便我可以更全面地理解问题空间?我不清楚新段落标准究竟是什么或为什么,或者它们预计何时发生。
  • 请查看更新的小提琴jsfiddle.net/InnovativeDave/j56c03ub,使用您的代码和测试数据文本。我想要发生的是粘贴的文本被划分为每个段落 300 个字符的限制

    并且它需要包含回车和退格功能的原因是用户需要在其中一个段落中有更多空间可能需要添加更多文本。此外,当他们按 Enter 键时,我希望上一段中的文本流入下一段,仍由 300 个字符组成,可能需要在其中创建一个新段落。

【解决方案4】:

请检查fiddle。我添加了一些代码来监听&lt;p&gt; 元素按键并进行所需的文本操作。

$(function() {
  $("#Go").on('click', function() {
    var $p, a = [];
    var theText = $('textarea').val();
    var numberOfCharacters = 300;
    while (theText.length) {
      while (theText.length > numberOfCharacters &&
        theText.charAt(numberOfCharacters) !== ' ') {
        numberOfCharacters++;
      }

      $p = $("<p contenteditable class='text'>" + theText.substring(0, numberOfCharacters) + "<\/p>")
        .on('keydown', function(e) {
          var p = this;
          setTimeout(function() {
            if (e.which === 13) {
              var i;
              var k = $(p).html().split('<br>');
              if ((i = a.indexOf(p)) > -1 && a[i + 1])
                $(a[i + 1]).html(k.pop() + ' ' + $(a[i + 1]).html());

              $(p).html(k.join('<br>'));
            }
          });
        });

      a.push($p.get(0));

      $("#text_land").append("<br><\/br>", $p, "<br><\/br>");

      theText = theText.substring(numberOfCharacters);
      numberOfCharacters = 300;
    }
  })
})
$('select').on('change', function() {
  var targets = $('#text_land p'),
    property = this.dataset.property;
  targets.css(property, this.value);
}).prop('selectedIndex', 0);
//(end);
@media print {
  p {
    page-break-inside: avoid;
  }
}
p {
  position: relative;
}
@media print {
  .no-print,
  .no-print * {
    display: none !important;
  }
}
p {
  border-style: solid;
}
p {
  color: #000;
}
p {
  display: block;
  text-align: justify;
  border-width: 5px;
  font-size: 19px;
}
p {
  overflow: hidden;
  height: 300px;
  width: 460px;
  word-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div align="center">
  <h4 align="center"><u>Paste text in the field below to divide text into
        paragraphs.</u></h4>
  <br>
  <br>
  <textarea placeholder="Type text here, then press the button below." cols="50" id="textarea1" rows="10">
  </textarea>
  <br>
  <br>
  <button id="Go">Divide Text into Paragraphs!</button>
</div>
<hr>
<h2 align="center">Divided Text Will Appear Below:</h2>
<div>
  <div align="center" id="text_land" style="font-family: monospace">
  </div>
</div>

【讨论】:

  • 我希望粘贴的文本被分成每段 300 个字符的限制

    并且需要包括回车和退格功能以防用户需要更多空间他们可能想要添加更多文本的段落。但是,此代码不会在编辑时将内容流入下一段,并隐藏每个动态

    标记下方的文本。是否有可能解决这些问题?

【解决方案5】:

你能检查一下这个Fiddle。好吧,我不确定这是否是您想要的。我只是在可编辑段落上添加事件来控制所需的输出。

$(function() {
  $("#Go").on('click', function() {
    var theText = $('textarea').val();
    var numberOfCharacters = 300;
    while (theText.length) {
      while (theText.length > numberOfCharacters &&
        theText.charAt(numberOfCharacters) !== ' ') {
        numberOfCharacters++;
      }
      $("#text_land").append("<br><\/br><p>" + theText.substring(
          0, numberOfCharacters) +
        "<\/p><br><\/br>");
      theText = theText.substring(numberOfCharacters);
      numberOfCharacters = 300;
      $('p').attr('contenteditable', 'true');
      $("p").addClass("text");
    }
  })
});
$(document).on('keyup', 'p.text', function(e) {
  if (e.keyCode == 13) {
    var extend = $(this).find("div").html();
    $(this).next().next().next().next().next().prepend(extend).focus();
    $(this).find("div").remove();
  }
});
$('select').on('blur keyup paste', function() {
  var targets = $('#text_land p'),
    property = this.dataset.property;
  targets.css(property, this.value);
}).prop('selectedIndex', 0);
(end);
@media print {
  p {
    page-break-inside: avoid;
  }
}
p {
  position: relative;
}
@media print {
  .no-print,
  .no-print * {
    display: none !important;
  }
}
p {
  border-style: solid;
}
p {
  color: #000;
}
p {
  display: block;
  text-align: justify;
  border-width: 5px;
  font-size: 19px;
}
p {
  overflow: hidden;
  height: 300px;
  width: 460px;
  word-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<div align="center">
  <h4 align="center"><u>Paste text in the field below to divide text into
        paragraphs.</u></h4>
  <br>
  <br>
  <textarea placeholder="Type text here, then press the button below." cols="50" id="textarea1" rows="10"></textarea>
  <br>
  <br>
  <button id="Go">Divide Text into Paragraphs!</button>
</div>
<hr>
<h2 align="center">Divided Text Will Appear Below:</h2>
<div>
  <div align="center" id="text_land" style="font-family: monospace">
  </div>
</div>

【讨论】:

  • 但是,当一个动态段落被填充时,文本需要溢出到下一个段落标记,并且用户可能希望在其中一个框中的段落文本之间添加一个空格。因此,虽然此代码确实将文本移动到下一个框,但溢出的文本仍然不可见,并将整个文本部分移动到下一个框,而不是补偿现有文本以确保它平等地适合每个框。
【解决方案6】:

将此事件绑定到您的每个段落,

$('.text').bind("DOMSubtreeModified", function () {
                        var text = $(this).html();
                        var newLineIndex = text.indexOf('&nbsp;');
                        if (newLineIndex != -1) {
                            var currentP = text.substring(0, newLineIndex);
                            var newP = text.substring(newLineIndex + 11, text.length - 6);
                            $(this).html(currentP);
                            var nextElement = $(this).next();
                            if (nextElement != null) {
                                // append rest of line to next paragraph
                                nextPara = newP + nextElement.html();
                                nextElement.html(nextPara);
                            }
                            else {
                                // Else, create new paragraph
                                $(this).after('<br><\/br> <p contenteditable="true" class="text">' + newP + '</p>');
                            }
                        }
                    });

所以,你的整个代码应该是这样的,

$(function () {
            $("#Go").on('click', function () {
                var theText = $('textarea').val();
                var numberOfCharacters = 300;
                while (theText.length) {
                    while (theText.length > numberOfCharacters &&
                        theText.charAt(numberOfCharacters) !== ' ') {
                        numberOfCharacters++;
                    }
                    $("#text_land").append("<br><\/br><p>" + theText.substring(
                            0, numberOfCharacters) +
                        "<\/p><br><\/br>");
                    theText = theText.substring(numberOfCharacters);
                    numberOfCharacters = 300;
                    $('p').attr('contenteditable', 'true');
                    $("p").addClass("text");

                    $('.text').bind("DOMSubtreeModified", function () {
                        var text = $(this).html();
                        var newLineIndex = text.indexOf('&nbsp;');
                        if (newLineIndex != -1) {
                            var currentP = text.substring(0, newLineIndex);
                            var newP = text.substring(newLineIndex + 11, text.length - 6);
                            $(this).html(currentP);
                            var nextElement = $(this).next();
                            if (nextElement != null) {
                                // append rest of line to next paragraph
                                nextPara = newP + nextElement.html();
                                nextElement.html(nextPara);
                            }
                            else {
                                // Else, create new paragraph
                                $(this).after('<br><\/br> <p contenteditable="true" class="text">' + newP + '</p>');
                            }
                        }
                    })
                }
            })
        })
        $('select').on('change', function () {
            var targets = $('#text_land p'),
                property = this.dataset.property;
            targets.css(property, this.value);
        }).prop('selectedIndex', 0);

如有任何疑问,请随时提出。

【讨论】:

  • 但是,此代码似乎无法正常工作。是否可以在生成段落后,让用户按下回车键,如果可能的话,将他们的内容无缝地向下移动到下面的段落中?并且在按下退格按钮时也适用相同的内容,以便内容向上移动到上一段?出现的问题是,当按下回车键时,由于 css 中的溢出属性,文本似乎隐藏了文本。
【解决方案7】:

我认为 CSS 属性:white-space: pre-wrap 可能是您正在寻找的:

https://jsfiddle.net/dbz3mwsb/1

【讨论】:

    【解决方案8】:

    如果我正确理解您的问题,您可以添加如下内容:

    $('#text_land').keyup(function(e) {
      if(e.keyCode == '13') {
        $(this).append("<br><br><p contenteditable='true' class='text'></p>");
        $('p.text:last-child').focus();
      }
    });
    

    然后,当您键入时,只要用户按 Enter,它就会即时生成新框。这是完整的示例:https://jsfiddle.net/2hcfbp2h/6/

    【讨论】:

    • 但是,目标是如果前一个框中的文本溢出,用户可以按 Enter 将该内容向下移动到新框中。如果用户按下退格按钮来恢复他们的更改,这也适用。
    【解决方案9】:

    npm 包paragraph-builder 将连续文本分割成均匀分布的段落,并且所有段落的字数大致相同。您可以定义段落的字数。

    此段落构建器节点脚本从连续文本生成段落。它输出一个文本,其中每个段落的大小大致相同,从而在文本中提供均匀的段落分布。它不会将文本拆分为“1.2”等数字。

    有一个选项可以定义段落之间的分隔符,或者您可以将段落提取到一个字符串数组中,您可以从中应用 html 标记 &lt;p&gt;。检查其文档以获得进一步说明。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-28
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-28
      • 1970-01-01
      相关资源
      最近更新 更多