Làm cách nào để giữ ngắt dòng khi nhận văn bản từ một vùng văn bản?


96

Tôi đang nhận được giá trị trong một vùng văn bản khi người dùng nhấn gửi. Sau đó, tôi lấy giá trị này và đặt nó ở nơi khác trên trang. Tuy nhiên, khi tôi làm điều này, nó làm mất các ký tự dòng mới khiến đầu ra khá xấu.

Đây là văn bản mà tôi đang truy cập:

<textarea id="post-text" class="form-control" rows="3" placeholder="What's up?" required></textarea>

Đây là mã JavaScript truy cập bài đăng và phiên âm nó.

var post = document.createElement('p');
var postText = document.getElementById('post-text').value;
post.append(postText);
var card = document.createElement('div');
card.append(post);
var cardStack = document.getElementById('#card-stack');
cardStack.prepend(card);

Khi đầu vào là một cái gì đó như:

Lịch trình nhóm:

Thứ Ba thực hành @ Tầng 5 (8 giờ tối - 11 giờ tối)

Thứ 5 tập tại tầng 5 (8 giờ tối - 11 giờ tối)

Chủ nhật thực hành @ (9 giờ tối - 12 giờ sáng)

Đầu ra là:

Lịch học nhóm: Thứ 3 tập @ Tầng 5 (8 giờ tối - 11 giờ tối) Thứ 5 luyện tập @ Tầng 5 (8 giờ tối - 11 giờ tối) Chủ nhật luyện tập @ (9 giờ tối - 12 giờ sáng)

Vậy có cách nào để bảo toàn ngắt dòng không?


1
nếu bạn được phép sử dụng jQuery điều này có thể giúp bạn: copy-từ-textarea-to-div bảo quản-linebreaks cách khác này có thể giúp bảo vệ-linebreaks-in-textarea-input
Kevin Kloet

1
Các ngắt dòng thực sự được giữ nguyên, phần tử đích chỉ được đặt để bỏ qua chúng trong khi hiển thị văn bản nhưng nếu bạn kiểm tra nó, bạn sẽ thấy chúng ở đây. Câu trả lời của Stefano chỉ đơn giản là đặt mục tiêu không còn bỏ qua chúng nữa, có lẽ là cách tốt nhất để đi.
phổ

2
Xin lỗi nitpick, nhưng getElementByIdchức năng từ dòng thứ 2 đến dòng cuối cùng nằm ở đâu? Tôi giả sử rằng bạn đã xác định nó ở nơi khác hoặc bạn quên document.
chạy thận

Câu trả lời:


177

Giải pháp đơn giản nhất là chỉ cần tạo kiểu cho phần tử bạn đang chèn văn bản vào bằng thuộc tính CSS sau:

white-space: pre-wrap;

Thuộc tính này làm cho khoảng trắng và dòng mới trong các phần tử phù hợp được xử lý giống như bên trong a <textarea>. Nghĩa là, khoảng trắng liên tiếp không được thu gọn và các dòng bị ngắt ở các dòng mới rõ ràng (nhưng cũng được bao bọc tự động nếu chúng vượt quá chiều rộng của phần tử).

Do một số câu trả lời được đăng ở đây cho đến nay dễ bị chèn HTML (ví dụ: vì họ gán đầu vào của người dùng không thoát cho innerHTML) hoặc có lỗi, hãy để tôi đưa ra một ví dụ về cách thực hiện điều này một cách an toàn và chính xác, dựa trên mã gốc của bạn:


Lưu ý rằng, giống như mã gốc của bạn, đoạn mã ở trên sử dụng append()prepend(). Tại thời điểm viết bài này, những chức năng đó vẫn được coi là thử nghiệm và không được hỗ trợ đầy đủ bởi tất cả các trình duyệt. Nếu bạn muốn an toàn và vẫn tương thích với các trình duyệt cũ hơn, bạn có thể thay thế chúng khá dễ dàng như sau:

  • element.append(otherElement)có thể được thay thế bằng element.appendChild(otherElement);
  • element.prepend(otherElement)có thể được thay thế bằng element.insertBefore(otherElement, element.firstChild);
  • element.append(stringOfText)có thể được thay thế bằng element.appendChild(document.createTextNode(stringOfText));
  • element.prepend(stringOfText)có thể được thay thế bằng element.insertBefore(document.createTextNode(stringOfText), element.firstChild);
  • như một trường hợp đặc biệt, nếu elementtrống, cả hai element.append(stringOfText)element.prepend(stringOfText)chỉ có thể được thay thế bằng element.textContent = stringOfText.

Đây là đoạn mã tương tự như trên, nhưng không sử dụng append()hoặc prepend():


Ps. Nếu bạn thực sự muốn làm điều này mà không sử dụng thuộc tính CSS white-space, một giải pháp thay thế sẽ là thay thế rõ ràng bất kỳ ký tự dòng mới nào trong văn bản bằng <br>các thẻ HTML. Phần khó khăn là, để tránh đưa vào các lỗi tinh vi và các lỗ hổng bảo mật tiềm ẩn, trước tiên bạn phải thoát khỏi bất kỳ siêu ký tự HTML nào (tối thiểu &<) trong văn bản trước khi thực hiện thay thế này.

Có lẽ cách đơn giản và an toàn nhất để làm điều đó là để trình duyệt xử lý việc thoát HTML cho bạn, như sau:

var post = document.createElement('p');
post.textContent = postText;
post.innerHTML = post.innerHTML.replace(/\n/g, '<br>\n');

Lưu ý rằng, mặc dù điều này sẽ sửa lỗi ngắt dòng, nhưng nó sẽ không ngăn các khoảng trắng liên tiếp bị thu gọn bởi trình kết xuất HTML. Có thể (đại loại) mô phỏng điều đó bằng cách thay thế một số khoảng trắng trong văn bản bằng các khoảng trắng không ngắt, nhưng thành thật mà nói, điều đó trở nên khá phức tạp đối với một thứ có thể được giải quyết bằng một dòng CSS.


2
Đây dường như là câu trả lời toàn diện nhất. Tại sao nó bị bỏ phiếu? Nếu nó chứa thông tin không chính xác, vui lòng chia sẻ.
Ethan Vander Horn

4
white-space: pre-line phù hợp với tôi, vì pre-wrap có chú thích trên dòng đầu tiên.
dev4life

1
Cảm ơn anh bạn. Bạn làm cho tôi ngày
thatman

Vì vậy, vấn đề là tôi có thể nhìn thấy khoảng trắng trong vùng văn bản, nhưng khi tôi nhận được chúng ở phần cuối API và chúng được gửi vào email, nó không bảo toàn khoảng trắng.
Apurva Kunkulol

@ApurvaKunkulol: Điều đó có vẻ như có vấn đề trong mã phía máy chủ của bạn. Bạn có thể đặt một câu hỏi mới về nó, nhưng bạn cần cung cấp một ví dụ có thể tái tạo tối thiểu để giải thích vấn đề.
Ilmari Karonen

23

Vùng chứa đích phải có white-space:prekiểu dáng. Hãy thử nó dưới đây.

<script>
function copycontent(){
 var content = document.getElementById('ta').value;
 document.getElementById('target').innerText = content;
}
</script>
<textarea id='ta' rows='3'>
  line 1
  line 2
  line 3
</textarea>
<button id='btn' onclick='copycontent();'>
Copy
</button>
<p id='target' style='white-space:pre'>

</p>


10
pre-wraphoặc pre-linesẽ tốt hơn. prengăn dòng ngắt dòng để một dòng văn bản rất dài sẽ ép thanh cuộn ngang.
Salman A

10
Mã này dễ bị chèn HTML vì bạn đang chỉ định đầu vào của người dùng không thoát cho innerHTML. Trong trường hợp này, chỉ cần thay thế innerHTMLbằng textContentsẽ khắc phục được.
Ilmari Karonen

1
@IlmariKaronen Điều đó sẽ phá vỡ mọi thứ. Bạn cần đặt innerText textContent . Chỉ cài đặt textContentsẽ không hoạt động trong IE (bất kỳ phiên bản nào) và chỉ cài đặt có innerTextthể không hoạt động trên Chrome trong tương lai và sẽ không hoạt động trên Firefox.
Ismael Miguel

3
@IsmaelMiguel: Thật lạ - Tôi đang đăng cái này từ IE 11, và nó hoạt động tốt ở đây. Rõ ràng IE đã được hỗ trợ textContentkể từ phiên bản 9.
Ilmari Karonen

2
@IlmariKaronen Điều đó thật kỳ lạ ... Tôi không biết điều đó. Nhưng nó là một ý kiến ​​hay innerTextnếu bạn cần IE8.
Ismael Miguel

7

function get() {
  var arrayOfRows = document.getElementById("ta").value.split("\n");
  var docfrag = document.createDocumentFragment();
  
  var p = document.getElementById("result");
  while (p.firstChild) {
    p.removeChild(p.firstChild);
  }
  
  arrayOfRows.forEach(function(row, index, array) {
    var span = document.createElement("span");
    span.textContent = row;
    docfrag.appendChild(span);
    if(index < array.length - 1) {
      docfrag.appendChild(document.createElement("br"));
    }
  });

  p.appendChild(docfrag);
}
<textarea id="ta" rows=3></textarea><br>
<button onclick="get()">get</button>
<p id="result"></p>

Bạn có thể chia các hàng textarea thành mảng:

var arrayOfRows = postText.value.split("\n");

Sau đó, sử dụng nó để tạo, có thể, nhiều thẻ p hơn ...


3
@IlmariKaronen đã nói gì: mã này không chính xác vì bạn đang gán plaintext ( textarea.value) cho thuộc tính mong đợi HTML ( innerHTML). Đây là một lỗi loại gây ra các vấn đề từ văn bản bị hỏng đến lỗ hổng bảo mật. Thay vì sử dụng innerHTML, bạn có thể làm appendChildvới document.createTextNode(text)document.createElement('br').
Kos

1
Một cách tốt để làm cho điều đó hiệu quả hơn là document.createDocumentFragment.
Kos

1
@IlmariKaronen, Kos, đây không phải là câu hỏi về bảo mật cũng như sự thành thạo. Tuy nhiên, tôi đã tối ưu hóa nó.
kolodi

3
@misher: OP đã yêu cầu một cách để duy trì các ngắt dòng, không phải cho một cách để duy trì các ngắt dòng cho phép chèn HTML. Nhận một lỗ hổng bảo mật miễn phí khi bạn yêu cầu trợ giúp để sửa lỗi giao diện người dùng giống như nhận được một cái kẹp miễn phí trong miếng bánh khi bạn yêu cầu một chiếc bánh hamburger. Dù sao, vì mã "được tối ưu hóa" của bạn dường như không còn dễ bị tấn công, tôi đã xóa phiếu phản đối của mình.
Ilmari Karonen

3

Đây là một ý tưởng vì bạn có thể có nhiều dòng mới trong một hộp văn bản:

 var text=document.getElementById('post-text').value.split('\n');
 var html = text.join('<br />');

Giá trị HTML này sẽ giữ nguyên dòng mới. Hi vọng điêu nay co ich.


1
Điều này cũng sẽ tạo ra sự kết hợp giữa đầu vào của người dùng không thoát và các thẻ HTML, điều này sẽ tạo ra lỗ hổng chèn HTML nếu htmlchuỗi kết quả thực sự được hiển thị dưới dạng HTML.
Ilmari Karonen

@IlmariKaronen - Vì vậy, mối quan tâm của bạn là ai đó có thể tấn công mình? OP không đề cập đến bất kỳ loại cơ sở dữ liệu nào. Làm thế nào để một người dùng nhập sẽ ảnh hưởng đến người dùng khác theo bất kỳ cách nào? Có thể đây là thứ chỉ dành cho mắt OPs và không có nhu cầu vệ sinh (nếu nó thậm chí có bất kỳ nhu cầu nào).
Jesse

1
@Jesse: Nói chung, thật khó để chắc chắn rằng đầu vào của người dùng đến từ một nguồn đáng tin cậy. Ngay cả khi kẻ tấn công không có cách nào để đưa trực tiếp văn bản vào vùng văn bản, thì đã có rất nhiều loại vi-rút trên mạng xã hội đã lây lan bằng cách thuyết phục những người dùng ngây thơ thông qua kỹ thuật xã hội sao chép-dán nội dung nào đó vào một trường nhập dễ bị tấn công. Bên cạnh đó, ngay cả khi đầu vào thực sự có thể được tin cậy 100%, mã này vẫn xáo trộn bất kỳ văn bản nào có chứa siêu ký tự HTML như &hoặc <. Ngay cả khi bảo mật không phải là mối quan tâm, đó vẫn là một lỗi.
Ilmari Karonen

@IlmariKaronen - Tôi không lo lắng gì về một cuộc tấn công nhưng cảm ơn bạn vì thông tin này!
Ethan Vander Horn

3

Bạn có thể đặt widthdiv bằng cách sử dụng Javascript và thêm white-space:pre-wrapvào p tag, điều này sẽ ngắt nội dung textarea của bạn ở cuối mỗi dòng.

document.querySelector("button").onclick = function gt(){
var card = document.createElement('div');
card.style.width = "160px";
card.style.background = "#eee";
var post = document.createElement('p');
var postText = document.getElementById('post-text').value;
post.style.whiteSpace = "pre-wrap";
card.append(post);
post.append(postText);
document.body.append(card);
}
<textarea id="post-text" class="form-control" rows="3" placeholder="What's up?" required>
Group Schedule:

Tuesday practice @ 5th floor (8pm - 11 pm)

Thursday practice @ 5th floor (8pm - 11 pm)

Sunday practice @ (9pm - 12 am)</textarea>
<br><br>
<button>Copy!!</button>


3

Tôi cho rằng bạn không muốn nội dung văn bản của mình được phân tích cú pháp dưới dạng HTML. Trong trường hợp này, bạn chỉ có thể đặt nó là văn bản rõ ràng để trình duyệt không coi nó là HTML và không xóa các dòng mới Không cần CSS hoặc xử lý trước.

<script>
function copycontent(){
 var content = document.getElementById('ta').value;
 document.getElementById('target').innerText = content;
}
</script>
<textarea id='ta' rows='3'>
  line 1
  line 2
  line 3
</textarea>
<button id='btn' onclick='copycontent();'>
Copy
</button>
<p id='target'></p>


2

Các câu hỏi tương tự ở đây

phát hiện ngắt dòng trong đầu vào vùng văn bản

phát hiện ngắt dòng trong vùng văn bản

Bạn có thể thử điều này:

var submit = document.getElementById('submit');

submit.addEventListener('click', function(){
var textContent = document.querySelector('textarea').value;
  
document.getElementById('output').innerHTML = textContent.replace(/\n/g, '<br/>');
  

});
<textarea cols=30 rows=10 >This is some text
this is another text

Another text again and again</textarea>
<input type='submit' id='submit'>


<p id='output'></p>

document.querySelector('textarea').value;sẽ lấy nội dung văn bản của vùng văn bản và textContent.replace(/\n/g, '<br/>')sẽ tìm tất cả các ký tự dòng mới trong mã nguồn /\n/gtrong nội dung và thay thế nó bằng dấu ngắt dòng html <br/>.


Một tùy chọn khác là sử dụng <pre> thẻ html . Xem bản demo bên dưới

var submit = document.getElementById('submit');

submit.addEventListener('click', function(){

  var content = '<pre>';
  
  var textContent = document.querySelector('textarea').value;
  
  content += textContent;
  
  content += '</pre>';

  document.getElementById('output').innerHTML = content;

});
<textarea cols=30 rows=10>This is some text
this is another text

Another text again and again </textarea>
<input type='submit' id='submit'>

<div id='output'> </div>


2
Vui lòng đọc lại câu hỏi một lần nữa. Người đăng đang hỏi cách giữ ngắt dòng khi đặt văn bản từ một vùng văn bản trên một trang, không phải bên trong một vùng văn bản khác.
Jesse

1
Ví dụ đầu tiên của bạn là lỗi và không hoạt động. (Bạn thậm chí không bao giờ gán kết quả của textContent.replace()bất kỳ thứ gì.) Ví dụ thứ hai của bạn dễ bị lỗi chèn HTML giống như một số câu trả lời khác, bởi vì bạn đang chỉ định đầu vào của người dùng không thoát cho innerHTML(và ví dụ đầu tiên của bạn sẽ dễ bị tổn thương như nhau, nếu bạn đã thử để thực sự làm bất cứ điều gì hữu ích với đầu ra của replace()cuộc gọi).
Ilmari Karonen

Cảm ơn bạn! Outlook 2013 thực sự biết <pre> là gì
user1566694
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.