以下fiddle允许将文字粘贴到<textarea>
并生成相等的段落,动态<p>
由相同数量的字符组成
发生的问题是;来自先前动态生成的段落<p>
中的文本在每个标记内溢出,并且不会正确地继续到下一个动态段落。因此,用户是否可以按Enter并将该内容向下移动到下一个现有段落中,同时仍然动态地自动保留现有格式?
如果可以提供新的Fiddle,我将非常感激,因为我还不熟悉编码。再一次,小提琴可以找到here。
更新:一旦生成了段落,用户是否可以按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);
&#13;
@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;
}
&#13;
<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>
&#13;
答案 0 :(得分:6)
用户可以按Enter键并将该内容向下移动 下一个现有段落,同时仍保留现有段落 动态自动格式化
如果我理解正确,你想要的是,一旦文本被分成段落,然后用户将一些文本添加到其中一个并按 Enter ,那么剩余的文本应该流动进入下一段,像以前一样分发溢出的文本。
类似地,当用户在段落的开头按 BackSpace 时,文本再次返回上一段,溢出的文本与之前的步骤一样分配到其他段落。
作为一种算法,你需要的是这样的东西:
p
的段落。keyup
元素p
事件
使用这种粗略的算法,您可以开始编码,看起来像这样:
注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个字符来分割此示例的文字。此外,这不会处理空格,并将分隔两者之间的单词。您需要在代码中执行此操作。 (#见下面的编辑)
用于捕获输入( 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
< / em>),删除该节点,在此之后添加所有段落的剩余文本,并删除剩余的段落。
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;
}
&#13;
* { 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; }
&#13;
<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>
&#13;
和你一起玩的小提琴:
小提琴:https://jsfiddle.net/abhitalks/jwnnn5oy/
修正了在字边界处断开的正则表达式。还添加了相同的非正则程序过程代码(在Op的原始代码中),以演示如何将其他代码段纳入其中并将其集成到其中的Op
Note 4 :关于Op的使用jQuery的评论,它与手头的问题无关。 jQuery只不过是JavaScript,对于他们来说,将片段片段合并到更大的代码库中应该是微不足道的。
更改集:添加了功能splitText
。
根据您的评论,如果您希望在用户输入时自动进行重新分发...那么您需要计算该段落中文本的长度,看看是否超过了您的块大小。如果是,则从该段开始重新分配。对退格做反向。
我最初发布的解决方案是为了满足您的要求,当用户按下任何文本之间进行输入以断开并将其分发到后续段落时。我不建议自动将其作为用户类型执行,因为更改对用户来说太过于刺激。
代码段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;
}
&#13;
* { 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; }
&#13;
<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>
&#13;
小提琴2:https://jsfiddle.net/abhitalks/hvhr4ds8/
注意5 :在小提琴中首先按Enter键以打破其间的一些文本,以便您能够看到重新分配如何发生当你输入。另外,请注意,由于不会破坏单词的逻辑,在重新分发之前需要多一些字符。
更改集:添加了功能redistributeAuto
。
答案 1 :(得分:1)
D3实际上非常适合这种情况。如果我理解正确,<p>
元素的添加和删除应该在编辑时自然出现并消失。
虽然有点粗糙,但在下面的示例中,检测到了一个新段落&#39;插入两个新行后。 <textarea>
值符合该条件的.split()
,并应用于右侧<div>
的{{1}}数组。因此,对于数据中的每个元素,我们只需输入/ exit / update data()
元素。我们在编辑文本的过程中得到了很好的简单添加和删除,而没有大量的DOM抖动。
通过一些改造,您可以将<p>
和<textarea>
合并到一个“wysiwyg”中。各种编辑...
<p>
&#13;
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);
&#13;
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;
}
&#13;
答案 2 :(得分:1)
请检查fiddle。我添加了一些代码来监听Error: This socket has been ended by the other party
元素按键并执行所需的文本操作。
<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;
}
答案 3 :(得分:1)
你可以查看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);
&#13;
@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;
}
&#13;
<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>
&#13;
答案 4 :(得分:1)
将此事件绑定到您的每个段落
$('.text').bind("DOMSubtreeModified", function () {
var text = $(this).html();
var newLineIndex = text.indexOf(' ');
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(' ');
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);
请随意对此提出任何疑问。
答案 5 :(得分:0)
我认为CSS属性:white-space: pre-wrap
可能是您正在寻找的内容:
答案 6 :(得分:0)
npm软件包paragraph-builder将连续文本分成均匀分布的段落,并且所有段落的字数大致相同。您可以定义段落的单词数。
此段落构建器节点脚本从连续文本生成段落。它输出一个文本,其中每个段落的大小大致相同,从而在文本中提供均匀的段落分布。它不会将数字拆分为“ 1.2”之类的数字。
有一个选项可以定义段落之间的分隔符,或者您可以将段落提取到一个字符串数组中,并从中应用html标签<p>
。检查其文档以进一步澄清。