Saya memiliki subset Markdown yang sangat kecil bersama dengan beberapa html kustom yang ingin saya parse menjadi komponen Bereaksi. Misalnya, saya ingin mengubah string berikut ini:
hello *asdf* *how* _are_ you !doing! today
Ke dalam array berikut:
[ "hello ", <strong>asdf</strong>, " ", <strong>how</strong>, " ", <em>are</em>, " you ", <MyComponent onClick={this.action}>doing</MyComponent>, " today" ]
dan kemudian mengembalikannya dari fungsi React render (React akan merender array dengan benar sebagai HTML yang diformat)
Pada dasarnya, saya ingin memberi pengguna pilihan untuk menggunakan set Markdown yang sangat terbatas untuk mengubah teks mereka menjadi komponen gaya (dan dalam beberapa kasus komponen saya sendiri!)
Tidak bijaksana untuk berbahaya SetInnerHTML, dan saya tidak ingin membawa ketergantungan eksternal, karena mereka semua sangat berat, dan saya hanya perlu fungsionalitas yang sangat dasar.
Saat ini saya melakukan sesuatu seperti ini, tetapi sangat rapuh, dan tidak berfungsi untuk semua kasus. Saya bertanya-tanya apakah ada cara yang lebih baik:
function matchStrong(result, i) {
let match = result[i].match(/(^|[^\\])\*(.*)\*/);
if (match) { result[i] = <strong key={"ms" + i}>{match[2]}</strong>; }
return match;
}
function matchItalics(result, i) {
let match = result[i].match(/(^|[^\\])_(.*)_/); // Ignores \_asdf_ but not _asdf_
if (match) { result[i] = <em key={"mi" + i}>{match[2]}</em>; }
return match;
}
function matchCode(result, i) {
let match = result[i].match(/(^|[^\\])```\n?([\s\S]+)\n?```/);
if (match) { result[i] = <code key={"mc" + i}>{match[2]}</code>; }
return match;
}
// Very brittle and inefficient
export function convertMarkdownToComponents(message) {
let result = message.match(/(\\?([!*_`+-]{1,3})([\s\S]+?)\2)|\s|([^\\!*_`+-]+)/g);
if (result == null) { return message; }
for (let i = 0; i < result.length; i++) {
if (matchCode(result, i)) { continue; }
if (matchStrong(result, i)) { continue; }
if (matchItalics(result, i)) { continue; }
}
return result;
}
Ini pertanyaan saya sebelumnya yang mengarah ke pertanyaan ini.
font _italic *and bold* then only italic_ and normal
? Apa yang akan menjadi hasil yang diharapkan? Atau akankah itu tidak pernah disarangkan?asdf*
tanpa menghilang)Jawaban:
Bagaimana itu bekerja?
Ini bekerja dengan membaca sepotong string demi sepotong, yang mungkin bukan solusi terbaik untuk string yang sangat panjang.
Setiap kali parser mendeteksi bongkahan kritis sedang dibaca, yaitu
'*'
atau tag penurunan harga lainnya, ia mulai menguraikan potongan elemen ini hingga parser menemukan tag penutupnya.Ini berfungsi pada string multi-line, lihat kode misalnya.
Peringatan
Anda belum menentukan, atau saya bisa salah memahami kebutuhan Anda, jika ada kebutuhan untuk mengurai tag yang tebal dan miring , solusi saya saat ini mungkin tidak berfungsi dalam kasus ini.
Jika Anda perlu, untuk bekerja dengan kondisi di atas, cukup komentari di sini dan saya akan mengubah kode.
Pembaruan pertama: tweak bagaimana perlakuan markdown diperlakukan
Tag tidak lagi hardcoded, sebaliknya mereka adalah peta di mana Anda dapat dengan mudah memperluas agar sesuai dengan kebutuhan Anda.
Memperbaiki bug yang Anda sebutkan di komentar, terima kasih telah menunjukkan masalah ini = hal
Pembaruan kedua: tag markdown multi-panjang
Cara termudah untuk mencapai ini: mengganti multi-panjang karakter dengan unicode yang jarang digunakan
Meskipun metode
parseMarkdown
ini belum mendukung tag multi-panjang, kami dapat dengan mudah mengganti tag multi-panjang dengan sederhanastring.replace
ketika mengirimrawMarkdown
prop kami .Untuk melihat contohnya dalam praktik ini, lihat
ReactDOM.render
, yang terletak di akhir kode.Bahkan jika aplikasi Anda mendukung banyak bahasa, ada karakter unicode yang tidak valid yang masih dideteksi oleh JavaScript, mis .:
"\uFFFF"
bukan unicode yang valid, jika saya ingat dengan benar, tetapi JS masih dapat membandingkannya ("\uFFFF" === "\uFFFF" = true
)Pada awalnya mungkin terlihat hack-y tetapi, tergantung pada kasus penggunaan Anda, saya tidak melihat masalah besar dengan menggunakan rute ini.
Cara lain untuk mencapai ini
Nah, kita bisa dengan mudah melacak potongan terakhir
N
(di manaN
sesuai dengan panjang tag multi-panjang terpanjang).Akan ada beberapa penyesuaian yang harus dilakukan dengan cara loop di dalam metode
parseMarkdown
berperilaku, yaitu memeriksa apakah potongan saat ini merupakan bagian dari tag multi-panjang, jika itu digunakan sebagai tag; jika tidak, dalam kasus seperti``k
, kita harus menandainya sebagainotMultiLength
atau sesuatu yang serupa dan mendorong potongan itu sebagai konten.Kode
Tautan ke kode (TypeScript) https://codepen.io/ludanin/pen/GRgNWPv
Tautan ke kode (vanilla / babel) https://codepen.io/ludanin/pen/eYmBvXw
sumber
This must be *bold*
denganThis must be *bo_ld*
. Itu menyebabkan HTML yang dihasilkan menjadi cacatSepertinya Anda mencari solusi kecil yang sangat mendasar. Bukan "monster super" seperti
react-markdown-it
:)Saya ingin merekomendasikan Anda https://github.com/developit/snarkdown yang terlihat sangat ringan dan menyenangkan! Hanya 1kb dan sangat sederhana, Anda dapat menggunakannya & memperluasnya jika Anda memerlukan fitur sintaks lainnya.
Daftar tag yang didukung https://github.com/developit/snarkdown/blob/master/src/index.js#L1
Memperbarui
Hanya memperhatikan tentang komponen reaksi, melewatkannya di awal. Jadi itu bagus untuk Anda, saya percaya untuk mengambil perpustakaan sebagai contoh dan mengimplementasikan komponen yang diperlukan khusus Anda untuk menyelesaikannya tanpa menetapkan HTML berbahaya. Perpustakaannya cukup kecil dan jelas. Bersenang-senanglah dengan itu! :)
sumber
Hasil:
Hasil tes Regexp
Penjelasan:
Anda dapat menentukan tag Anda di bagian ini
[*|!|_]
:, setelah salah satu dari mereka dicocokkan, tag itu akan ditangkap sebagai grup dan dinamai sebagai "tag_begin".Dan kemudian
(?<content>\w+)
menangkap konten yang dibungkus oleh tag.Tag akhir harus sama dengan yang sebelumnya cocok, jadi di sini digunakan
\k<tag_begin>
, dan jika lulus tes maka tangkap sebagai grup dan beri nama "tag_end", itulah yang(?<tag_end>\k<tag_begin>))
dikatakan.Di JS Anda telah menyiapkan tabel seperti ini:
Gunakan tabel ini untuk mengganti tag yang cocok.
Sting.replace memiliki String.replace yang berlebihan (regexp, fungsi) yang dapat mengambil grup yang ditangkap sebagai parameternya, kami menggunakan item yang diambil ini untuk mencari tabel dan menghasilkan string pengganti.
[Perbarui]
Saya telah memperbarui kode, saya menyimpan yang pertama kalau-kalau ada orang lain yang tidak perlu komponen reaksi, dan Anda bisa lihat ada sedikit perbedaan di antara mereka.
sumber
console.log
output, Anda akan melihat array penuh dengan string, bukan komponen Bereaksi aktual: jsfiddle.net/xftswh41Anda bisa melakukannya seperti ini:
sumber
A working solution purely using Javascript and ReactJs without dangerouslySetInnerHTML.
Pendekatan
Pencarian karakter demi karakter untuk elemen penurunan harga. Segera setelah ditemukan, cari tag penutup untuk hal yang sama dan kemudian ubah menjadi html.
Tag didukung di cuplikan
Input dan Output dari snippet:
JsFiddle: https://jsfiddle.net/sunil12738/wg7emcz1/58/
Kode:
Penjelasan terperinci (dengan contoh):
Misalkan jika string adalah
How are *you* doing?
Jauhkan pemetaan untuk simbol untuk tag["How are "]
dan mulai loop dalam sampai Anda menemukan * berikutnya.Now next between * and * needs to be bold
, kami mengonversinya dalam elemen html dengan teks dan langsung mendorong dalam array di mana Tag = b dari peta. Jika Anda melakukannya<Tag>text</Tag>
, reaksi konversi internal menjadi teks dan dorong ke array. Sekarang array adalah ["apa kabar", Anda ]. Istirahat dari lingkaran dalamHow are <b>you</b> doing?
Note: <b>you</b> is html and not text
Catatan : Bersarang juga dimungkinkan. Kita perlu memanggil logika di atas dalam rekursi
Untuk menambahkan dukungan Tag baru
map
objek dengan kunci sebagai karakter dan nilai sebagai tag yang sesuaiApakah ini mendukung bersarang? Tidak
Apakah ini mendukung semua kasus penggunaan yang disebutkan oleh OP? Iya
Semoga ini bisa membantu.
sumber
asdf
akan dirender<pre>asdf</pre>
dengan latar belakang gelap, bukan? Biarkan saya tahu ini dan saya akan melihat. Bahkan Anda bisa mencobanya sekarang. Pendekatan sederhana adalah: Dalam solusi di atas, ganti `` `dalam teks dengan karakter khusus seperti ^ atau ~ dan petakan ke pra tag. Maka itu akan bekerja dengan baik. Pendekatan lain membutuhkan beberapa pekerjaan lagi<pre>asdf</pre>
. Terima kasih!pre
dukungan tag juga. Beritahu saya jika berhasil