Kait bereaksi kecil untuk mengubah elemen menjadi permukaan konten yang dapat diterjemahkan sepenuhnya & dapat diedit, seperti editor kode, menggunakan ContentEditable (dan Magic)
useEditable adalah kait kecil yang memungkinkan elemen untuk contenteditable sambil tetap sepenuhnya dapat diterjemahkan. Ini sangat ideal untuk membuat editor kode kecil atau textarea prosa hanya dalam 2kB !
Ini bertujuan untuk memungkinkan elemen apa pun dapat diedit sementara masih dapat membuat elemen bereaksi normal untuk itu - tidak ada innerHTML dan harus berurusan dengan beroperasi dengan atau rendering ke HTML mentah, atau memulai proyek editor penuh dari awal.
Lihatlah demo lengkap di CodeSandBox dengan prism-react-renderer !
Pertama-tama instal use-editable bersama react :
yarn add use-editable
# or
npm install --save use-editable Anda kemudian dapat mengimpor useEditable dan meneruskannya HTMLElement ref dan handler onChange .
import React , { useState , useRef } from 'react' ;
import { useEditable } from 'use-editable' ;
const RainbowCode = ( ) => {
const [ code , setCode ] = useState ( 'function test() {}nconsole.log("hello");' ) ;
const editorRef = useRef ( null ) ;
useEditable ( editorRef , setCode ) ;
return (
< div className = "App" >
< pre
style = { { whiteSpace : 'pre-wrap' , fontFamily : 'monospace' } }
ref = { editorRef }
>
{ code . split ( / r?n / ) . map ( ( content , i , arr ) => (
< React . Fragment key = { i } >
< span style = { { color : `hsl( ${ ( ( i % 20 ) * 17 ) | 0 } , 80%, 50%)` } } >
{ content }
</ span >
{ i < arr . length - 1 ? 'n' : null }
</ React . Fragment >
) ) }
</ pre >
</ div >
) ;
} ; Dan begitu saja kami telah terhubung useEditable untuk editorRef kami, yang menunjuk ke elemen <pre> yang sedang diterjemahkan, dan untuk setCode yang mendorong negara kami yang berisi beberapa kode.
Perpustakaan ini telah diuji dan harus berfungsi dengan baik menggunakan:
Ada masalah yang diketahui di IE 11 karena metode MutationObserver tidak dapat membaca node teks yang telah dihapus melalui yang contenteditable .
Secara tradisional, ada tiga opsi ketika memilih permukaan pengeditan di React. Salah satu yang bisa pergi untuk proyek besar seperti prosemirror / codemirror atau yang serupa yang mengambil kendali atas banyak acara pengeditan dan render dan karenanya lebih opini, atau dimungkinkan untuk hanya menggunakan contenteditable dan membuat HTML mentah yang diganti dalam konten elemen, atau terakhir orang dapat menggabungkan textarea dengan div yang tumpang tindih yang renungan.
Ketiga opsi tidak mengizinkan banyak kustomisasi dalam hal apa yang sebenarnya diterjemahkan atau menempatkan pembatasan yang tidak masuk akal tentang betapa mudahnya membuat dan mengelola konten yang dapat diedit.
Jadi apa yang membuat rendering ke elemen contenteditable begitu keras?
Biasanya ini sulit karena mereka mengedit DOM secara langsung. Hal ini menyebabkan sebagian besar perpustakaan rendering, seperti bereaksi dan pra -bereaksi menjadi bingung, karena DOM virtual yang mendasarinya tidak lagi cocok dengan struktur DOM yang sebenarnya. Untuk mencegah masalah ini use-editable menciptakan MutationObserver , yang mengawasi semua perubahan yang dilakukan pada elemen contenteditable . Sebelum melaporkan perubahan ini untuk bereaksi pertama -tama menggulung semua perubahan pada DOM sehingga React melihat apa yang diharapkannya.
Selain itu, ia juga mempertahankan posisi karet saat ini, pemilihan, dan mengembalikannya setelah bereaksi telah memperbarui DOM itu sendiri. Ini adalah teknik yang agak umum untuk editor contenteditable , tetapi penambahan MutationObserver adalah yang memungkinkan use-editable untuk membiarkan perpustakaan tampilan lain memperbarui konten elemen.
Saat ini konten teks elemen yang diberikan pada akhirnya harus cocok dengan input kode, atau implementasi Anda harus dapat mengonversi konten teks yang diberikan kembali menjadi apa yang Anda gunakan sebagai status. Ini adalah batasan bagaimana pekerjaan contenteditable , karena mereka hanya akan menangkap konten DOM yang sebenarnya. Karena use-editable tidak bertujuan untuk menjadi komponen penuh yang mengelola siklus render, tidak harus menjaga keadaan tambahan, tetapi hanya akan meneruskan teks DOM kembali ke panggilan balik onChange .
Menggunakan panggilan balik onChange Anda juga akan menerima objek Position yang menggambarkan posisi kursor, nomor baris saat ini, dan konten jalur hingga kursor, yang berguna untuk seruggestion otomatis, yang kemudian dapat diterapkan dengan fungsi update yang useEditable pengembalian yang dapat digunakan untuk memperbarui posisi kursor.
Argumen pertama adalah elementRef dan menerima objek ref dari Type RefObject<HTMLElement> yang menunjuk ke elemen yang harus dapat diedit. Ref ini dibiarkan null atau berubah selama runtime hook. Selama perubahan ref dipicu oleh React, semuanya harus berperilaku seperti yang diharapkan.
Argumen kedua adalah onChange dan menerima panggilan balik tipe (text: string, pos: Position) => void yang disebut setiap kali konten perubahan contenteditable . Ini perlu diatur sehingga akan memicu rerender konten elemen.
text yang diterima onChange hanyalah representasi tekstual dari konten elemen, sedangkan Position yang diterimanya berisi posisi saat ini dari kursor, nomor garis (nol-indeks), dan konten baris saat ini hingga kursor, yang berguna untuk otosugestion.
Argumen ketiga adalah objek options opsional. Ini menerima dua opsi saat ini untuk mengubah perilaku pengeditan kait:
disabled menonaktifkan pengeditan pada yang dapat diedit dengan menghapus atribut contentEditable dari itu lagi.indentation mungkin sejumlah ruang yang ditampilkan untuk lekukan. Ini juga memungkinkan perilaku kunci Tab yang ditingkatkan, yang akan menindas garis saat ini atau mendedentasikan garis saat ini ketika shift diadakan (ketahuilah bahwa ini akan membuat editor bertindak sebagai perangkap fokus!) Ketika options.indentation diatur kemudian useEditable akan mencegah penyisipan karakter tab dan sebaliknya akan memasukkan jumlah putih yang ditentukan, yang membuat penanganan kolom jauh lebih mudah.
Selain itu, kait useEditable mengembalikan pegangan Edit dengan beberapa metode, seperti yang didokumentasikan di bawah ini.
Edit.update(content: string): void
Menggantikan seluruh konten yang dapat diedit sambil menyesuaikan posisi karet. Ini akan menggeser caret dengan perbedaan panjang antara konten saat ini dan konten yang ditularkan.
Edit.insert(append: string, offset?: number): void
Menyisipkan teks baru pada posisi caret sambil menghapus teks dalam kisaran offset (yang menerima offset negatif). Misalnya, ketika offset diatur ke -1 maka satu karakter dihapus ke kiri karet sebelum memasukkan teks baru. Ketika diatur ke 2 maka dua karakter di sebelah kanan karet dihapus. Teks append juga dapat diatur ke string kosong untuk hanya menerapkan penghapusan tanpa memasukkan teks apa pun. Ketika teks apa pun dipilih maka itu hanya dihapus terlebih dahulu dan offset diabaikan.
Edit.move(pos: number | { row: number; column: number }): void
Ini menggerakkan caret ke posisi yang ditentukan. Posisi dapat berupa indeks karakter ( number ) atau koordinat yang menentukan row dan column secara terpisah.
Edit.getState(): { text: string; position: Position }
Metode ini memungkinkan mendapatkan keadaan saat ini yang dapat diedit, yang sama dengan apa yang biasanya diterima onChange . Ini berguna saat menambahkan tindakan pengeditan khusus di pawang kunci ke bawah atau ketika secara terprogram meniru onChange sebaliknya, sementara yang dapat diedit dipilih.
react-live , yang telah saya kerjakan memiliki salah satu editor kecil contenteditable . (Tetapi dengan pembaruan HTML mentah)react-simple-code-editor adalah perpustakaan pertama (?) Untuk menggunakan tekstara split dan implementasi permukaan rendering, yang menyajikan seperti apa seharusnya API pengeditan yang bagus.codejar berisi trik terbaik untuk mengelola pilihan, meskipun tidak memiliki beberapa solusi Firefox. Ini juga menggunakan penyorotan / pembaruan HTML mentah.codemirror.next adalah sumber yang tak ternilai untuk melihat berbagai teknik saat menangani input teks dan trik pembaruan DOM. Stable: DECEPIDABLE tidak berencana untuk mengembangkan fitur baru untuk proyek ini. Kami masih menanggapi laporan bug dan masalah keamanan. Kami masih menyambut PRS untuk proyek ini, tetapi PR yang mencakup fitur baru harus kecil dan mudah diintegrasikan dan tidak boleh termasuk perubahan perubahan.