Bagaimana cara mempertahankan jeda baris saat mendapatkan teks dari textarea?

96

Saya mendapatkan nilai di textarea saat pengguna mengklik kirim. Saya kemudian mengambil nilai ini dan meletakkannya di tempat lain di halaman. Namun, ketika saya melakukan ini, karakter baris baru hilang sehingga hasilnya cukup jelek.

Berikut textarea yang saya akses:

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

Berikut adalah kode JavaScript yang mengakses posting dan menyalinnya.

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

Ketika inputnya seperti:

Jadwal Grup:

Latihan Selasa @ lantai 5 (8 malam - 11 malam)

Latihan Kamis @ lantai 5 (8 malam - 11 malam)

Latihan Minggu @ (9 malam - 12 pagi)

Outputnya adalah:

Jadwal Kelompok: Latihan Selasa @ lantai 5 (8 malam - 11 malam) Latihan Kamis @ lantai 5 (8 malam - 11 malam) Latihan Minggu @ (9 malam - 12 pagi)

Jadi, apakah ada cara untuk mempertahankan jeda baris?

Ethan Vander Horn
sumber
1
jika Anda diizinkan untuk menggunakan jQuery, ini mungkin membantu Anda: copy-from-textarea-to-div-preserving-linebreaks sebagai alternatif, ini mungkin membantu melestarikan-line-break-in-textarea-input
Kevin Kloet
1
Jeda baris sebenarnya dipertahankan, elemen target hanya disetel untuk mengabaikannya saat menampilkan teks tetapi jika Anda memeriksanya, Anda akan melihatnya ada di sini. Jawaban Stefano hanya menetapkan target untuk tidak lagi mengabaikannya, mungkin cara terbaik untuk melakukannya.
spektrum
2
Maaf untuk nitpick, tapi di mana getElementByIdfungsinya dari baris ke-2 hingga terakhir? Saya berasumsi apakah Anda mendefinisikannya di tempat lain atau Anda lupa document.
trisis

Jawaban:

176

Solusi termudah adalah dengan hanya memberi gaya pada elemen tempat Anda memasukkan teks dengan properti CSS berikut:

white-space: pre-wrap;

Properti ini menyebabkan spasi dan baris baru di dalam elemen yang cocok diperlakukan dengan cara yang sama seperti di dalam a <textarea>. Artinya, spasi berurutan tidak diciutkan, dan garis diputus pada baris baru yang eksplisit (tetapi juga dibungkus secara otomatis jika melebihi lebar elemen).

Mengingat bahwa beberapa jawaban yang diposting di sini sejauh ini rentan terhadap injeksi HTML (misalnya karena mereka menetapkan masukan pengguna yang tidak lolos innerHTML) atau buggy, izinkan saya memberikan contoh cara melakukannya dengan aman dan benar, berdasarkan kode asli Anda:


Perhatikan bahwa, seperti kode asli Anda, cuplikan di atas menggunakan append()dan prepend(). Sampai tulisan ini dibuat, fungsi-fungsi tersebut masih dianggap eksperimental dan tidak didukung sepenuhnya oleh semua browser. Jika Anda ingin aman dan tetap kompatibel dengan browser lama, Anda dapat menggantinya dengan mudah seperti berikut:

  • element.append(otherElement)bisa diganti dengan element.appendChild(otherElement);
  • element.prepend(otherElement)bisa diganti dengan element.insertBefore(otherElement, element.firstChild);
  • element.append(stringOfText)bisa diganti dengan element.appendChild(document.createTextNode(stringOfText));
  • element.prepend(stringOfText)bisa diganti dengan element.insertBefore(document.createTextNode(stringOfText), element.firstChild);
  • sebagai kasus khusus, jika elementkosong, keduanya element.append(stringOfText)dan element.prepend(stringOfText)dapat dengan mudah diganti element.textContent = stringOfText.

Berikut cuplikan yang sama seperti di atas, tetapi tanpa menggunakan append()atau prepend():


Ps. Jika Anda benar-benar ingin melakukan ini tanpa menggunakan white-spaceproperti CSS , solusi alternatifnya adalah mengganti secara eksplisit karakter baris baru apa pun dalam teks dengan <br>tag HTML. Bagian yang sulit adalah, untuk menghindari munculnya bug halus dan potensi celah keamanan, Anda harus terlebih dahulu keluar dari semua karakter meta HTML (minimal, &dan <) dalam teks sebelum Anda melakukan penggantian ini.

Mungkin cara termudah dan teraman untuk melakukannya adalah dengan membiarkan browser menangani pelolosan HTML untuk Anda, seperti ini:

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

Perhatikan bahwa, meskipun ini akan memperbaiki jeda baris, ini tidak akan mencegah spasi kosong yang berurutan diciutkan oleh perender HTML. Dimungkinkan untuk (semacam) meniru itu dengan mengganti beberapa spasi putih dalam teks dengan spasi non-breaking, tapi sejujurnya, itu menjadi agak rumit untuk sesuatu yang dapat diselesaikan dengan mudah dengan satu baris CSS.

Ilmari Karonen
sumber
2
Ini sepertinya jawaban yang paling komprehensif. Mengapa tidak dipilih? Jika itu berisi informasi yang salah, silakan bagikan.
Ethan Vander Horn
4
white-space: pre-line bekerja untuk saya, karena pre-wrap memiliki lekukan pada baris pertama.
dev4life
1
Terima kasih Bung. Anda membuat hari saya
pria itu
Jadi masalahnya adalah saya bisa melihat spasi di area teks, tetapi ketika saya menerimanya di API end dan dikirim ke email, itu tidak menyimpan spasi.
Apurva Kunkulol
@ApurvaKunkulol: Sepertinya ada masalah pada kode sisi server Anda. Anda dapat mengajukan pertanyaan baru tentang hal itu, tetapi Anda harus memberikan contoh minimal yang dapat direproduksi yang menunjukkan masalah tersebut.
Ilmari Karonen
23

Penampung target harus memiliki white-space:pregaya. Coba di bawah ini.

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

Stefano Altieri
sumber
10
pre-wrapatau pre-lineakan lebih baik. premencegah penggabungan baris sehingga baris teks yang sangat panjang akan memaksa scrollbar horizontal.
Salman A
10
Kode ini rentan terhadap injeksi HTML, karena Anda menetapkan masukan pengguna tanpa konversi karakter ke innerHTML. Dalam hal ini, cukup mengganti innerHTMLdengan textContentakan memperbaikinya.
Ilmari Karonen
1
@IlmariKaronen Itu akan merusak segalanya. Anda perlu mengatur innerText dan textContent . Pengaturan saja textContenttidak akan berfungsi di IE (versi apa pun) dan hanya pengaturan innerTextmungkin tidak berfungsi di Chrome di masa mendatang dan tidak akan berfungsi di Firefox.
Ismael Miguel
3
@IsmaelMiguel: Aneh - Saya memposting ini dari IE 11, dan berfungsi dengan baik di sini. Rupanya IE telah mendukung textContentsejak versi 9.
Ilmari Karonen
2
@IlmariKaronen Aneh ... Saya tidak menyadarinya. Namun sebaiknya innerTextAnda menyertakannya jika Anda membutuhkan 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>

Anda dapat membagi baris textarea menjadi array:

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

Kemudian gunakan untuk menghasilkan, mungkin, lebih banyak tag p ...

kolodi
sumber
3
Apa yang dikatakan @IlmariKaronen: kode ini salah karena Anda menetapkan plaintext ( textarea.value) ke properti yang mengharapkan HTML ( innerHTML). Ini adalah jenis kesalahan yang menyebabkan masalah mulai dari teks rusak hingga lubang keamanan. Alih-alih menggunakan innerHTML, Anda dapat melakukannya appendChilddengan document.createTextNode(text)dan document.createElement('br').
Kos
1
Cara yang baik untuk membuatnya lebih efisien adalah document.createDocumentFragment.
Kos
1
@IlmariKaronen, Kos, ini bukan pertanyaan tentang keamanan atau efisiensi. Saya memang mengoptimalkannya.
kolodi
3
@misher: OP meminta cara untuk mempertahankan jeda baris, bukan cara untuk mempertahankan jeda baris dan mengizinkan injeksi HTML. Mendapatkan celah keamanan gratis saat Anda meminta bantuan untuk memperbaiki bug UI adalah seperti mendapatkan paku payung gratis di patty saat Anda meminta hamburger. Bagaimanapun, karena kode "yang dioptimalkan" tampaknya tidak lagi rentan, saya telah menghapus suara negatif saya.
Ilmari Karonen
3

Berikut ini idenya karena Anda mungkin memiliki beberapa baris baru di kotak teks:

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

Nilai HTML ini akan mempertahankan baris baru. Semoga ini membantu.

reza
sumber
1
Ini juga akan menghasilkan campuran masukan pengguna yang tidak lolos dan tag HTML, yang akan membuat kerentanan injeksi HTML jika htmlstring yang dihasilkan benar-benar dirender sebagai HTML.
Ilmari Karonen
@IlmariKaronen - Jadi kekhawatiran Anda adalah bahwa seseorang mungkin menyerang dirinya sendiri? OP tidak menyebutkan jenis database apa pun. Bagaimana satu masukan pengguna memengaruhi pengguna lain dengan cara apa pun? Mungkin ini adalah sesuatu yang hanya untuk mata OP saja dan 0 kebutuhan akan sanitasi (bahkan jika memang membutuhkannya sama sekali).
Jesse
1
@ Jesse: Secara umum, sulit untuk memastikan bahwa masukan pengguna berasal dari sumber tepercaya. Meskipun tidak ada cara bagi penyerang untuk secara langsung memasukkan teks ke dalam area teks, ada banyak virus media sosial yang telah menyebar dengan meyakinkan pengguna yang naif melalui rekayasa sosial untuk menyalin-menempel sesuatu ke bidang entri yang rentan. Selain itu, meskipun masukan benar-benar dapat dipercaya 100%, kode ini masih merusak teks apa pun yang berisi karakter meta HTML seperti &atau <. Sekalipun keamanan bukan masalah, itu masih bug.
Ilmari Karonen
@IlmariKaronen - Saya sama sekali tidak khawatir tentang serangan, tetapi terima kasih atas informasi ini!
Ethan Vander Horn
3

Anda bisa mengatur widthdiv menggunakan Javascript dan menambahkan white-space:pre-wrapuntuk p tag, istirahat ini konten textarea Anda di akhir setiap baris.

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>

frnt
sumber
3

Saya kira Anda tidak ingin konten textarea Anda diurai sebagai HTML. Dalam kasus ini, Anda dapat mengaturnya sebagai teks biasa sehingga browser tidak memperlakukannya sebagai HTML dan tidak menghapus baris baru. Tidak diperlukan CSS atau praproses.

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

tkausl
sumber
2

Pertanyaan serupa ada di sini

mendeteksi jeda baris di input area teks

mendeteksi jeda baris di area teks

Anda dapat mencoba ini:

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;akan mendapatkan konten teks dari textarea dan textContent.replace(/\n/g, '<br/>')akan menemukan semua karakter baris baru dalam kode sumber/\n/g di konten dan menggantinya dengan baris baru html <br/>.


Pilihan lainnya adalah menggunakan <pre> tag html . Lihat demo di bawah ini

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>

Abk
sumber
2
Harap baca ulang pertanyaannya lagi. Poster menanyakan bagaimana mempertahankan jeda baris saat meletakkan teks dari textarea pada halaman, bukan di dalam textarea lain.
Jesse
1
Contoh pertama Anda adalah buggy dan tidak berfungsi. (Anda bahkan tidak pernah menetapkan hasil textContent.replace()apa pun.) Contoh kedua Anda rentan terhadap bug injeksi HTML yang sama seperti beberapa jawaban lainnya, karena Anda menetapkan input pengguna yang tidak lolos innerHTML(dan contoh pertama Anda akan sama-sama rentan, jika Anda mencoba untuk benar-benar melakukan sesuatu yang berguna dengan hasil replace()panggilan).
Ilmari Karonen
Terima kasih! Outlook 2013 sebenarnya mengetahui apa itu <pre>
user1566694