使用 JS 扩展文本区域以适应高度会变慢。改为查看 div 和 contenteditable
Expanding textarea to fit height gets slow with JS. Looking into div and contenteditable instead
我使用 Autosize 使文本区域适合文本的高度。它工作正常,但在数百个文本区域(这可能是预期的)上变得非常慢。
我研究过将 div
与 contenteditable
一起使用,经过大量尝试后,我找到了一个可以满足我要求的解决方案,但它似乎有点老套,尤其是在 Firefox 中用奇怪的双换行处理。我能做些什么来进一步完善它或以更简洁的方式实现上述技巧吗?
在 Mac 上的 Firefox 中,如果您在中间某处编辑文本,您仍然会在输入时遇到 2 个换行符。有什么解决方法吗?
// Paste fix for contenteditable
$('[contenteditable]').on('paste', function (e) {
e.preventDefault();
if (window.clipboardData)
{
content = window.clipboardData.getData('Text');
if (window.getSelection)
{
var selObj = window.getSelection();
var selRange = selObj.getRangeAt(0);
selRange.deleteContents();
selRange.insertNode(document.createTextNode(content));
}
}
else if (e.originalEvent.clipboardData)
{
content = (e.originalEvent || e).clipboardData.getData('text/plain');
document.execCommand('insertText', false, content);
}
});
// Set Current Value on Focus
$(document).on('focus', '.edit-area', function() {
var $self = $(this);
if( $self.is("div") )
{
cur_val = $self[0].innerText.trim();
}
else
{
cur_val = $self.val();
}
});
// Blur on enter and fix line-breaks especially for FF
$(document).on('keydown', '.edit-area', function(e) {
var $self = $(this);
var esc = e.keyCode == 27;
var nl = e.keyCode == 13;
if (esc)
{
// Restore if ESC
if( $self.is("div") )
{
$self.text(cur_val);
}
else
{
$self.val(cur_val);
}
$self.blur();
}
else if (nl)
{
if( $self.is("div") )
{
/* Tried this instead of the document.execCommand below but it leaves a space in there which I'd love to avoid
e.preventDefault(); //Prevent default browser behavior
if (window.getSelection) {
var selection = window.getSelection(),
range = selection.getRangeAt(0),
br = document.createElement("br"),
textNode = document.createTextNode($("<div> </div>").text()); //Passing " " directly will not end up being shown correctly
range.deleteContents();//required or not?
range.insertNode(br);
range.collapse(false);
range.insertNode(textNode);
range.selectNodeContents(textNode);
selection.removeAllRanges();
selection.addRange(range);
return false;
}*/
/* Tried this but it still gives an extra br in FF
document.execCommand('insertHTML', false, '<br><br>'); // fix for line-breaks
return false;*/
// This Seems to be the best solution so far...
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
var sel, node, offset, text, textBefore, textAfter, range;
sel = window.getSelection();
// the node that contains the caret
node = sel.anchorNode;
// if ENTER was pressed while the caret was inside the input field
// prevent the browsers from inserting <div>, <p>, or <br> on their own
e.preventDefault();
// the caret position inside the node
offset = sel.anchorOffset;
// insert a '\n' character at that position
text = node.textContent;
textBefore = text.slice( 0, offset );
textAfter = text.slice( offset ) || ' ';
node.textContent = textBefore + '\n' + textAfter;
// position the caret after that new-line character
range = document.createRange();
range.setStart( node, offset + 1 );
range.setEnd( node, offset + 1 );
// update the selection
sel.removeAllRanges();
sel.addRange( range );
}
}
}
});
// Save data on blur
$(document).on('blur', '.edit-area', function() {
var $self = $(this);
if( $self.is("div") )
{
var value = $self[0].innerText.trim();
$self.text(value);
}
else
{
if( $self.val() instanceof Array )
{
var value = $self.val();
}
else
{
var value = trim($self.val());
$self.val(value);
}
}
if( String(value) == String(cur_val) )
{
return false; // Return false if value is current value
}
// Save to database here...
alert("Save this to database:\n\n"+value);
});
div.edit-area[contenteditable] {
outline: none;
white-space: pre-wrap;
}
div.edit-area[contenteditable]:empty:before {
content: '-';
}
div.edit-area[contenteditable]:focus:before {
color: transparent;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" class="edit-area">Editable text with
line-breaks
preserved, enter hack, paste fix, trimmed result and no html</div>
在 Safari、Chrome 和 Mac 的 FF 中工作和测试。
// Paste fix for contenteditable
$('[contenteditable]').on('paste', function (e) {
e.preventDefault();
if (window.clipboardData)
{
content = window.clipboardData.getData('Text');
if (window.getSelection)
{
var selObj = window.getSelection();
var selRange = selObj.getRangeAt(0);
selRange.deleteContents();
selRange.insertNode(document.createTextNode(content));
}
}
else if (e.originalEvent.clipboardData)
{
content = (e.originalEvent || e).clipboardData.getData('text/plain');
document.execCommand('insertText', false, content);
}
});
// Set Current Value on Focus
$(document).on('focus', '.edit-area', function() {
var $self = $(this);
if( $self.is("div") )
{
cur_val = $self[0].innerText.trim();
}
else
{
cur_val = $self.val();
}
});
// Blur on enter and fix line-breaks especially for FF
$(document).on('keydown', '.edit-area', function(e) {
var $self = $(this);
var esc = e.keyCode == 27;
var nl = e.keyCode == 13;
if (esc)
{
// Restore if ESC
if( $self.is("div") )
{
$self.text(cur_val);
}
else
{
$self.val(cur_val);
}
$self.blur();
}
else if (nl)
{
if( $self.is("div") )
{
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
var sel, node, offset, text, textBefore, textAfter, range;
sel = window.getSelection();
// the node that contains the caret
node = sel.anchorNode;
// if ENTER was pressed while the caret was inside the input field
// prevent the browsers from inserting <div>, <p>, or <br> on their own
e.preventDefault();
// the caret position inside the node
offset = sel.anchorOffset;
// insert a '\n' character at that position
text = node.textContent;
textBefore = text.slice( 0, offset );
textAfter = text.slice( offset ) || ' ';
node.textContent = textBefore + '\n' + textAfter;
// position the caret after that new-line character
range = document.createRange();
range.setStart( node, offset + 1 );
range.setEnd( node, offset + 1 );
// update the selection
sel.removeAllRanges();
sel.addRange( range );
}
}
}
});
// Save data on blur
$(document).on('blur', '.edit-area', function() {
var $self = $(this);
if( $self.is("div") )
{
var value = $self[0].innerText.trim();
$self.text(value);
}
else
{
if( $self.val() instanceof Array )
{
var value = $self.val();
}
else
{
var value = trim($self.val());
$self.val(value);
}
}
if( String(value) == String(cur_val) )
{
return false; // Return false if value is current value
}
// Save to database here...
alert("Save this to database:\n\n"+value);
});
div.edit-area[contenteditable] {
outline: none;
white-space: pre-wrap;
}
div.edit-area[contenteditable]:empty:before {
content: '-';
}
div.edit-area[contenteditable]:focus:before {
color: transparent;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" class="edit-area">Editable text with
line-breaks
preserved, enter hack, paste fix, trimmed result and no html</div>
我使用 Autosize 使文本区域适合文本的高度。它工作正常,但在数百个文本区域(这可能是预期的)上变得非常慢。
我研究过将 div
与 contenteditable
一起使用,经过大量尝试后,我找到了一个可以满足我要求的解决方案,但它似乎有点老套,尤其是在 Firefox 中用奇怪的双换行处理。我能做些什么来进一步完善它或以更简洁的方式实现上述技巧吗?
在 Mac 上的 Firefox 中,如果您在中间某处编辑文本,您仍然会在输入时遇到 2 个换行符。有什么解决方法吗?
// Paste fix for contenteditable
$('[contenteditable]').on('paste', function (e) {
e.preventDefault();
if (window.clipboardData)
{
content = window.clipboardData.getData('Text');
if (window.getSelection)
{
var selObj = window.getSelection();
var selRange = selObj.getRangeAt(0);
selRange.deleteContents();
selRange.insertNode(document.createTextNode(content));
}
}
else if (e.originalEvent.clipboardData)
{
content = (e.originalEvent || e).clipboardData.getData('text/plain');
document.execCommand('insertText', false, content);
}
});
// Set Current Value on Focus
$(document).on('focus', '.edit-area', function() {
var $self = $(this);
if( $self.is("div") )
{
cur_val = $self[0].innerText.trim();
}
else
{
cur_val = $self.val();
}
});
// Blur on enter and fix line-breaks especially for FF
$(document).on('keydown', '.edit-area', function(e) {
var $self = $(this);
var esc = e.keyCode == 27;
var nl = e.keyCode == 13;
if (esc)
{
// Restore if ESC
if( $self.is("div") )
{
$self.text(cur_val);
}
else
{
$self.val(cur_val);
}
$self.blur();
}
else if (nl)
{
if( $self.is("div") )
{
/* Tried this instead of the document.execCommand below but it leaves a space in there which I'd love to avoid
e.preventDefault(); //Prevent default browser behavior
if (window.getSelection) {
var selection = window.getSelection(),
range = selection.getRangeAt(0),
br = document.createElement("br"),
textNode = document.createTextNode($("<div> </div>").text()); //Passing " " directly will not end up being shown correctly
range.deleteContents();//required or not?
range.insertNode(br);
range.collapse(false);
range.insertNode(textNode);
range.selectNodeContents(textNode);
selection.removeAllRanges();
selection.addRange(range);
return false;
}*/
/* Tried this but it still gives an extra br in FF
document.execCommand('insertHTML', false, '<br><br>'); // fix for line-breaks
return false;*/
// This Seems to be the best solution so far...
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
var sel, node, offset, text, textBefore, textAfter, range;
sel = window.getSelection();
// the node that contains the caret
node = sel.anchorNode;
// if ENTER was pressed while the caret was inside the input field
// prevent the browsers from inserting <div>, <p>, or <br> on their own
e.preventDefault();
// the caret position inside the node
offset = sel.anchorOffset;
// insert a '\n' character at that position
text = node.textContent;
textBefore = text.slice( 0, offset );
textAfter = text.slice( offset ) || ' ';
node.textContent = textBefore + '\n' + textAfter;
// position the caret after that new-line character
range = document.createRange();
range.setStart( node, offset + 1 );
range.setEnd( node, offset + 1 );
// update the selection
sel.removeAllRanges();
sel.addRange( range );
}
}
}
});
// Save data on blur
$(document).on('blur', '.edit-area', function() {
var $self = $(this);
if( $self.is("div") )
{
var value = $self[0].innerText.trim();
$self.text(value);
}
else
{
if( $self.val() instanceof Array )
{
var value = $self.val();
}
else
{
var value = trim($self.val());
$self.val(value);
}
}
if( String(value) == String(cur_val) )
{
return false; // Return false if value is current value
}
// Save to database here...
alert("Save this to database:\n\n"+value);
});
div.edit-area[contenteditable] {
outline: none;
white-space: pre-wrap;
}
div.edit-area[contenteditable]:empty:before {
content: '-';
}
div.edit-area[contenteditable]:focus:before {
color: transparent;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" class="edit-area">Editable text with
line-breaks
preserved, enter hack, paste fix, trimmed result and no html</div>
在 Safari、Chrome 和 Mac 的 FF 中工作和测试。
// Paste fix for contenteditable
$('[contenteditable]').on('paste', function (e) {
e.preventDefault();
if (window.clipboardData)
{
content = window.clipboardData.getData('Text');
if (window.getSelection)
{
var selObj = window.getSelection();
var selRange = selObj.getRangeAt(0);
selRange.deleteContents();
selRange.insertNode(document.createTextNode(content));
}
}
else if (e.originalEvent.clipboardData)
{
content = (e.originalEvent || e).clipboardData.getData('text/plain');
document.execCommand('insertText', false, content);
}
});
// Set Current Value on Focus
$(document).on('focus', '.edit-area', function() {
var $self = $(this);
if( $self.is("div") )
{
cur_val = $self[0].innerText.trim();
}
else
{
cur_val = $self.val();
}
});
// Blur on enter and fix line-breaks especially for FF
$(document).on('keydown', '.edit-area', function(e) {
var $self = $(this);
var esc = e.keyCode == 27;
var nl = e.keyCode == 13;
if (esc)
{
// Restore if ESC
if( $self.is("div") )
{
$self.text(cur_val);
}
else
{
$self.val(cur_val);
}
$self.blur();
}
else if (nl)
{
if( $self.is("div") )
{
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
var sel, node, offset, text, textBefore, textAfter, range;
sel = window.getSelection();
// the node that contains the caret
node = sel.anchorNode;
// if ENTER was pressed while the caret was inside the input field
// prevent the browsers from inserting <div>, <p>, or <br> on their own
e.preventDefault();
// the caret position inside the node
offset = sel.anchorOffset;
// insert a '\n' character at that position
text = node.textContent;
textBefore = text.slice( 0, offset );
textAfter = text.slice( offset ) || ' ';
node.textContent = textBefore + '\n' + textAfter;
// position the caret after that new-line character
range = document.createRange();
range.setStart( node, offset + 1 );
range.setEnd( node, offset + 1 );
// update the selection
sel.removeAllRanges();
sel.addRange( range );
}
}
}
});
// Save data on blur
$(document).on('blur', '.edit-area', function() {
var $self = $(this);
if( $self.is("div") )
{
var value = $self[0].innerText.trim();
$self.text(value);
}
else
{
if( $self.val() instanceof Array )
{
var value = $self.val();
}
else
{
var value = trim($self.val());
$self.val(value);
}
}
if( String(value) == String(cur_val) )
{
return false; // Return false if value is current value
}
// Save to database here...
alert("Save this to database:\n\n"+value);
});
div.edit-area[contenteditable] {
outline: none;
white-space: pre-wrap;
}
div.edit-area[contenteditable]:empty:before {
content: '-';
}
div.edit-area[contenteditable]:focus:before {
color: transparent;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" class="edit-area">Editable text with
line-breaks
preserved, enter hack, paste fix, trimmed result and no html</div>