继续dynamic文本到单独的<p>段落?

下面的小提琴允许将文本粘贴到一个<textarea>并且由相同数量的字符dynamic地生成为相等的段落。


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

如果能提供一个新的小提琴 ,那将是非常值得赞赏的,因为我还是新的编码。 再次,小提琴可以在这里find。

更新:一旦生成了段落,用户是否可以按下回车键,并在可能的情况下将其内容无缝移动到下面的段落中? 同样按下退格button时也是一样的,内容要移到上面那段? 出现的问题是,当按下Enter键时,文本似乎由于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> 

用户可以按Enter键并将该内容下移到下一个现有段落中,同时仍然保持现有格式的dynamic和自动

如果我正确地理解了你,你想要的是,一旦文本被分成段落,然后用户添加一些文本到其中一个,并按下Enter ,那么剩余的文本应该stream入下一个段落分布溢出文本平等较早完成。

类似地,当用户在段落开始时按下BackSpace时,文本又回到前一段落,并且如前所述将溢出的文本分配到其他段落中。

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

  1. 将初始文本划分为相同的块,并根据需要dynamic分配段落,以dynamic创build这些p
  2. 听取关于这些p元素的关键事件
  3. 如果按下Enter键
    • 3.1从其中按下Enter的地方提取剩余的文本
    • 3.2从下面的所有段落中提取文本,前面加上上面提取的溢出文本
    • 3.3删除下面的所有段落,并像我们在第1步中那样分发合并的文本
  4. 如果按键是BackSpace
    • 4.1检查是否在段落开头,是否有前面的段落
    • 4.2提取段落的文本并附加到下一段所有段落的文本中
    • 4.3删除所有段落,包括当前段落,并将提取的文本附加到前一段落。
    • 4.4像我们在第1步中那样分发合并的文本

用这个粗略的algorithm,你可以开始编码,看起来像这样:

注1 :这是所有的JavaScript,没有jQuery。
注2 :这是过分简化,你将需要进一步优化和制定出所有的边缘情况。

caching所需的元素并绑定事件处理程序:

 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); } 

通过dynamic创build所需数量的段落来重新排列/分发文本的逻辑:

 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个字符来分割文本。 而且,这不会处理空间,并将分隔中间的单词。 你需要在代码中这样做。 (#见下面的编辑)

input键码13 )和BackSpace键码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,则在当前段落的最后一个子元素之后提取文本( contenteditable将在按下Enter时产生一个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; } 

综合起来,这里是一个工作片段:

片段:

 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> 

很简单,如果我正确地理解你。

 $(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> 

D3实际上非常适合这个。 如果我正确理解了你, <p>元素的添加和删除应该在编辑时自然出现和消失。

这有点粗糙,但在下面的例子中,在插入两个新行后,“检测到”新段落。 <textarea>值是针对该条件的.split() ,并应用于右侧的<div> ,因为它是data()数组。 因此,对于数据中的每个元素,我们只需input/ exit / update <p>元素。 当我们编辑没有太多DOM抖动的文本时,我们可以轻松地添加和删除。

有了一些改进,你可以将<textarea><p>合并成一个“wysiwyg”编辑器。

 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="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> 

请检查小提琴 。 我添加了一些代码来收听<p>元素按键,并进行所需的文本操作。

 $(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> 

你能检查这小提琴吗? 那么我不知道这是你想要的。 我只是在可编辑的段落添加事件来控制所需的输出。

 $(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> 

把这个事件绑定到你的每一段,

 $('.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属性: white-space: pre-wrap可能是你要找的东西:

https://jsfiddle.net/dbz3mwsb/1

如果我正确理解你的问题,你可以添加这样的东西:

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

然后当你input的时候,只要用户input,它就会随时产生新的盒子。 以下是完整的示例: https : //jsfiddle.net/2hcfbp2h/6/