Membangun Editor Kode Web

Diterbitkan: 2022-03-10
Ringkasan cepat Jika Anda seorang pengembang yang berpikir untuk membangun platform yang memerlukan editor kode dalam satu atau lain bentuk, maka artikel ini cocok untuk Anda. Artikel ini menjelaskan cara membuat editor kode web yang menampilkan hasilnya secara real time dengan bantuan beberapa HTML, CSS, dan JavaScript.

Editor kode web online paling berguna saat Anda tidak memiliki kesempatan untuk menggunakan aplikasi editor kode, atau saat Anda ingin mencoba sesuatu di web dengan komputer atau bahkan ponsel Anda dengan cepat. Ini juga merupakan proyek yang menarik untuk dikerjakan karena memiliki pengetahuan tentang cara membuat editor kode akan memberi Anda ide tentang cara mendekati proyek lain yang mengharuskan Anda mengintegrasikan editor kode untuk menunjukkan beberapa fungsionalitas.

Berikut adalah beberapa konsep React yang perlu Anda ketahui untuk mengikuti artikel ini:

  • kait,
  • Struktur komponen,
  • komponen fungsional,
  • Atribut.

Menggunakan CodeMirror

Kami akan menggunakan perpustakaan bernama CodeMirror untuk membangun editor kami. CodeMirror adalah editor teks serbaguna yang diimplementasikan dalam JavaScript untuk browser. Ini terutama untuk mengedit kode dan dilengkapi dengan sejumlah mode bahasa dan add-on untuk fungsionalitas pengeditan lebih lanjut.

API pemrograman yang kaya dan sistem tema CSS tersedia untuk menyesuaikan CodeMirror agar sesuai dengan aplikasi Anda dan memperluasnya dengan fungsionalitas baru. Ini memberi kita fungsionalitas untuk membuat editor kode kaya yang berjalan di web dan menunjukkan kepada kita hasil kode kita secara real time.

Di bagian selanjutnya, kita akan menyiapkan proyek React baru kita dan menginstal perpustakaan yang kita butuhkan untuk membangun aplikasi web kita.

Membuat Proyek React Baru

Mari kita mulai dengan membuat proyek React baru. Di antarmuka baris perintah Anda, navigasikan ke direktori di mana Anda ingin membuat proyek Anda, dan mari buat aplikasi React dan beri nama code_editor :

 npx create-react-app code_editor

Setelah membuat aplikasi React baru, mari navigasikan ke direktori proyek tersebut di antarmuka baris perintah:

 cd code_editor

Ada dua perpustakaan yang perlu kita instal di sini: codemirror dan react-codemirror2 .

 npm install codemirror react-codemirror2

Setelah menginstal perpustakaan yang kita butuhkan untuk proyek ini, mari buat tab kita dan aktifkan peralihan tab di antara tiga tab yang akan muncul di editor kita (untuk HTML, CSS, dan JavaScript).

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

Komponen Tombol

Alih-alih membuat tombol individual, mari jadikan tombol sebagai komponen yang dapat digunakan kembali. Dalam proyek kami, tombol akan memiliki tiga contoh, sesuai dengan tiga tab yang kami butuhkan.

Buat folder bernama components di folder src . Di folder components baru ini, buat file JSX bernama Button.jsx .

Berikut adalah semua kode yang dibutuhkan dalam komponen Button :

 import React from 'react' const Button = ({title, onClick}) => { return ( <div> <button style={{ maxWidth: "140px", minWidth: "80px", height: "30px", marginRight: "5px" }} onClick={onClick} > {title} </button> </div> ) } export default Button

Berikut adalah penjelasan lengkap dari apa yang kami lakukan di atas:

  • Kami membuat komponen fungsional bernama Button , yang kemudian kami ekspor.
  • Kami merusak title dan onClick dari props yang masuk ke komponen. Di sini, title akan menjadi string teks, dan onClick akan menjadi fungsi yang dipanggil saat tombol diklik.
  • Selanjutnya, kami menggunakan elemen button untuk mendeklarasikan tombol kami, dan menggunakan atribut style untuk menata tombol kami agar terlihat rapi.
  • Kami menambahkan atribut onClick dan meneruskan alat peraga fungsi onClick kami yang telah dirusak ke dalamnya.
  • Hal terakhir yang Anda perhatikan kami lakukan di komponen ini adalah meneruskan {title} sebagai konten dari tag button . Ini memungkinkan kita untuk menampilkan judul secara dinamis, berdasarkan prop apa yang diteruskan ke instance komponen tombol saat dipanggil.

Sekarang kita telah membuat komponen tombol yang dapat digunakan kembali, mari kita lanjutkan dan membawa komponen kita ke App.js. Buka App.js dan impor komponen tombol yang baru dibuat:

 import Button from './components/Button';

Untuk melacak tab atau editor mana yang terbuka, kita memerlukan status deklarasi untuk menyimpan nilai editor yang terbuka. Menggunakan kait useState React, kita akan mengatur status yang akan menyimpan nama tab editor yang saat ini terbuka saat tombol tab itu diklik.

Inilah cara kami melakukannya:

 import React, { useState } from 'react'; import './App.css'; import Button from './components/Button'; function App() { const [openedEditor, setOpenedEditor] = useState('html'); return ( <div className="App"> </div> ); } export default App;

Di sini, kami menyatakan negara kami. Dibutuhkan nama editor yang sedang terbuka. Karena nilai html diteruskan sebagai nilai default negara bagian, editor HTML akan menjadi tab yang terbuka secara default.

Mari kita lanjutkan dan tulis fungsi yang akan menggunakan setOpenedEditor untuk mengubah nilai status saat tombol tab diklik.

Catatan: Dua tab mungkin tidak terbuka secara bersamaan, jadi kita harus mempertimbangkannya saat menulis fungsi kita.

Inilah fungsi kami, bernama onTabClick , terlihat seperti:

 import React, { useState } from 'react'; import './App.css'; import Button from './components/Button'; function App() { ... const onTabClick = (editorName) => { setOpenedEditor(editorName); }; return ( <div className="App"> </div> ); } export default App;

Di sini, kami melewati argumen fungsi tunggal, yang merupakan nama tab yang saat ini dipilih. Argumen ini akan diberikan di mana pun fungsi dipanggil, dan nama yang relevan dari tab itu akan diteruskan.

Mari buat tiga instance Button untuk tiga tab yang kita butuhkan:

 <div className="App"> <p>Welcome to the editor!</p> <div className="tab-button-container"> <Button title="HTML" onClick={() => { onTabClick('html') }} /> <Button title="CSS" onClick={() => { onTabClick('css') }} /> <Button title="JavaScript" onClick={() => { onTabClick('js') }} /> </div> </div>

Inilah yang kami lakukan:

  • Kami mulai dengan menambahkan tag p , pada dasarnya hanya untuk memberikan beberapa konteks tentang apa aplikasi kami.
  • Kami menggunakan tag div untuk membungkus tombol tab kami. Tag div membawa className yang akan kita gunakan untuk menata tombol menjadi tampilan grid di file CSS nanti dalam tutorial ini.
  • Selanjutnya, kami mendeklarasikan tiga instance dari komponen Button . Jika Anda ingat, komponen Button membutuhkan dua props, title dan onClick . Dalam setiap instance komponen Button , kedua props ini disediakan.
  • title prop mengambil judul tab.
  • Prop onClick mengambil fungsi, onTabClick , yang baru saja kita buat dan yang mengambil satu argumen: nama tab yang dipilih.

Berdasarkan tab yang saat ini dipilih, kami akan menggunakan operator ternary JavaScript untuk menampilkan tab secara kondisional. Ini berarti bahwa jika nilai dari status openedEditor diatur ke html (yaitu setOpenedEditor('html') ), maka tab untuk bagian HTML akan menjadi tab yang terlihat saat ini. Anda akan memahami ini dengan lebih baik seperti yang kami lakukan di bawah ini:

 ... return ( <div className="App"> ... <div className="editor-container"> { openedEditor === 'html' ? ( <p>The html editor is open</p> ) : openedEditor === 'css' ? ( <p>The CSS editor is open!!!!!!</p> ) : ( <p>the JavaScript editor is open</p> ) } </div> </div> ); ...

Mari kita bahas kode di atas dalam bahasa Inggris yang sederhana. Jika nilai openedEditor adalah html , maka tampilkan bagian HTML. Jika tidak, jika nilai dari openedEditor adalah css , maka tampilkan bagian CSS. Jika tidak, jika nilainya bukan html atau css , maka itu berarti nilainya harus js , karena kita hanya memiliki tiga kemungkinan nilai untuk status openedEditor ; jadi, maka kami akan menampilkan tab untuk JavaScript.

Kami menggunakan tag paragraf ( p ) untuk bagian yang berbeda dalam kondisi operator ternary. Saat kita melanjutkan, kita akan membuat komponen editor dan mengganti tag p dengan komponen editor itu sendiri.

Kami telah sampai sejauh ini! Ketika sebuah tombol diklik, itu menjalankan tindakan yang menyetel tab yang diwakilinya menjadi true , membuat tab itu terlihat. Berikut tampilan aplikasi kami saat ini:

GIF yang menunjukkan sakelar tab yang kami miliki saat ini.
GIF yang menunjukkan sakelar tab yang kami miliki saat ini. (Pratinjau besar)

Mari tambahkan sedikit CSS ke wadah div yang menahan tombol. Kami ingin tombol ditampilkan dalam kotak, alih-alih ditumpuk secara vertikal seperti pada gambar di atas. Buka file App.css Anda dan tambahkan kode berikut:

 .tab-button-container{ display: flex; }

Ingatlah bahwa kita menambahkan className="tab-button-container" sebagai atribut dalam tag div yang menahan tombol tiga-tab. Di sini, kami memberi gaya pada wadah itu, menggunakan CSS untuk mengatur tampilannya menjadi flex . Ini adalah hasilnya:

Kami menggunakan CSS untuk mengatur tampilannya menjadi fleksibel
(Pratinjau besar)

Banggalah dengan seberapa banyak yang telah Anda lakukan untuk sampai ke titik ini. Di bagian selanjutnya, kami akan membuat editor kami, mengganti tag p dengan mereka.

Membuat Editor

Karena kita telah menginstal perpustakaan yang akan kita kerjakan di dalam editor CodeMirror kita, mari kita buat file Editor.jsx kita di folder components .

komponen > Editor.jsx

Setelah membuat file baru kita, mari kita tulis beberapa kode awal di dalamnya:

 import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { return ( <div className="editor-container"> </div> ) } export default Editor

Inilah yang kami lakukan:

  • Kami mengimpor React bersama hook useState karena kami akan membutuhkannya.
  • Kami mengimpor file CSS CodeMirror (yang berasal dari perpustakaan CodeMirror yang kami instal, jadi Anda tidak perlu menginstalnya dengan cara khusus).
  • Kami mengimpor Controlled dari react-codemirror2 , mengganti namanya menjadi ControlledEditorComponent untuk membuatnya lebih jelas. Kami akan segera menggunakan ini.
  • Kemudian, kami mendeklarasikan komponen fungsional Editor kami, dan kami memiliki pernyataan return dengan div kosong, dengan className dalam pernyataan return untuk saat ini.

Dalam komponen fungsional kami, kami merusak beberapa nilai dari props, termasuk language , value , dan setEditorState . Ketiga props ini akan diberikan dalam setiap instance editor saat dipanggil di App.js .

Mari kita gunakan ControlledEditorComponent untuk menulis kode untuk editor kita. Inilah yang akan kami lakukan:

 import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/css/css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { return ( <div className="editor-container"> <ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, }} /> </div> ) } export default Editor

Mari kita telusuri apa yang kita lakukan di sini, menjelaskan beberapa istilah CodeMirror.

Mode CodeMirror menentukan bahasa yang dimaksudkan untuk editor. Kami mengimpor tiga mode karena kami memiliki tiga editor untuk proyek ini:

  1. XML: Mode ini untuk HTML. Ini menggunakan istilah XML.
  2. JavaScript: Ini ( codemirror/mode/javascript/javascript ) membawa mode JavaScript.
  3. CSS: Ini ( codemirror/mode/css/css ) membawa mode CSS.

Catatan: Karena editor dibuat sebagai komponen yang dapat digunakan kembali, kami tidak dapat menempatkan mode langsung di editor. Jadi, kami menyediakan mode melalui prop language yang kami destruktur. Tetapi ini tidak mengubah fakta bahwa mode perlu diimpor agar berfungsi.

Selanjutnya, mari kita bahas hal-hal di ControlledEditorComponent :

  • onBeforeChange
    Ini dipanggil kapan saja Anda menulis atau menghapus dari editor. Pikirkan ini seperti handler onChange yang biasanya Anda miliki di bidang input untuk melacak perubahan. Dengan menggunakan ini, kita akan bisa mendapatkan nilai editor kita kapan saja ada perubahan baru dan menyimpannya ke status editor kita. Kami akan menulis fungsi {handleChange} saat kami melanjutkan.
  • value = {value}
    Ini hanyalah konten editor pada waktu tertentu. Kami meneruskan value bernama prop yang didestruktur ke atribut ini. Alat peraga value adalah status yang memegang nilai editor itu. Ini akan diberikan dari contoh editor.
  • className ="code-mirror-wrapper"
    Nama kelas ini bukan gaya yang kami buat sendiri. Itu dipasok dari file CSS CodeMirror, yang kami impor di atas.
  • options
    Ini adalah objek yang mengambil fungsi berbeda yang kita inginkan untuk dimiliki oleh editor kita. Ada banyak opsi luar biasa di CodeMirror. Mari kita lihat yang kami gunakan di sini:
    • lineWrapping: true
      Ini berarti bahwa kode harus membungkus ke baris berikutnya ketika baris sudah penuh.
    • lint: true
      Ini memungkinkan linting.
    • mode: language
      Mode ini, seperti yang dibahas di atas, menggunakan bahasa yang akan digunakan editor. Bahasa telah diimpor di atas, tetapi editor akan menerapkan bahasa berdasarkan nilai language yang diberikan ke editor melalui prop.
    • lineNumbers: true
      Ini menentukan bahwa editor harus memiliki nomor baris untuk setiap baris.

Selanjutnya, kita dapat menulis fungsi handleChange untuk handler onBeforeChange :

 const handleChange = (editor, data, value) => { setEditorState(value); }

Handler onBeforeChange memberi kita akses ke tiga hal: editor, data, value .

Kami hanya membutuhkan value karena itulah yang ingin kami sampaikan di prop setEditorState kami. Prop setEditorState mewakili nilai yang ditetapkan untuk setiap status yang kami deklarasikan di App.js , yang menyimpan nilai untuk setiap editor. Saat kita melanjutkan, kita akan melihat bagaimana meneruskan ini sebagai prop ke komponen Editor .

Selanjutnya, kita akan menambahkan dropdown yang memungkinkan kita memilih tema yang berbeda untuk editor. Jadi, mari kita lihat tema di CodeMirror.

Tema CodeMirror

CodeMirror memiliki beberapa tema yang dapat kita pilih. Kunjungi situs web resmi untuk melihat demo berbagai tema yang tersedia. Mari buat dropdown dengan tema berbeda yang dapat dipilih pengguna di editor kami. Untuk tutorial ini, kami akan menambahkan lima tema, tetapi Anda dapat menambahkan sebanyak yang Anda suka.

Pertama, mari impor tema kita di komponen Editor.js :

 import 'codemirror/theme/dracula.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/mdn-like.css'; import 'codemirror/theme/the-matrix.css'; import 'codemirror/theme/night.css';

Selanjutnya, buat larik dari semua tema yang telah kita impor:

 const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night']

Mari deklarasikan kait useState untuk menyimpan nilai tema yang dipilih, dan atur tema default sebagai dracula :

 const [theme, setTheme] = useState("dracula")

Mari kita buat dropdown:

 ... return ( <div className="editor-container"> <div style={{marginBottom: "10px"}}> <label for="cars">Choose a theme: </label> <select name="theme" onChange={(el) => { setTheme(el.target.value) }}> { themeArray.map( theme => ( <option value={theme}>{theme}</option> )) } </select> </div> // the rest of the code comes below... </div> ) ...

Pada kode di atas, kami menggunakan tag HTML label untuk menambahkan label ke dropdown kami, dan kemudian menambahkan tag HTML select untuk membuat dropdown kami. Tag option di elemen select mendefinisikan opsi yang tersedia di dropdown.

Karena kita perlu mengisi dropdown dengan nama tema di themeArray yang kita buat, kita menggunakan metode array .map untuk memetakan themeArray dan menampilkan nama secara individual menggunakan tag option .

Tunggu — kita belum selesai menjelaskan kode di atas. Di tag select pembuka, kami meneruskan atribut onChange untuk melacak dan memperbarui status theme setiap kali nilai baru dipilih di dropdown. Setiap kali opsi baru dipilih di dropdown, nilainya didapat dari objek yang dikembalikan kepada kami. Selanjutnya, kami menggunakan setTheme dari kait status kami untuk menetapkan nilai baru menjadi nilai yang dimiliki status.

Pada titik ini, kami telah membuat dropdown kami, mengatur status tema kami, dan menulis fungsi kami untuk mengatur status dengan nilai baru. Hal terakhir yang perlu kita lakukan untuk membuat CodeMirror menggunakan tema kita adalah meneruskan tema ke objek options di ControlledEditorComponent . Di objek options , mari tambahkan nilai bernama theme , dan atur nilainya ke nilai status untuk tema yang dipilih, juga bernama theme .

Inilah yang akan terlihat seperti ControlledEditorComponent sekarang:

 <ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }} />

Sekarang, kami telah membuat dropdown dari berbagai tema yang dapat dipilih dari dalam editor.

Berikut tampilan kode lengkap di Editor.js saat ini:

 import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import 'codemirror/theme/dracula.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/mdn-like.css'; import 'codemirror/theme/the-matrix.css'; import 'codemirror/theme/night.css'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/css/css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { const [theme, setTheme] = useState("dracula") const handleChange = (editor, data, value) => { setEditorState(value); } const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night'] return ( <div className="editor-container"> <div style={{marginBottom: "10px"}}> <label for="themes">Choose a theme: </label> <select name="theme" onChange={(el) => { setTheme(el.target.value) }}> { themeArray.map( theme => ( <option value={theme}>{theme}</option> )) } </select> </div> <ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }} /> </div> ) } export default Editor

Hanya ada satu className yang perlu kita gaya. Buka App.css dan tambahkan gaya berikut:

 .editor-container{ padding-top: 0.4%; }

Sekarang setelah editor kita siap, mari kembali ke App.js dan menggunakannya di sana.

src > App.js

Hal pertama yang perlu kita lakukan adalah mengimpor komponen Editor.js di sini:

 import Editor from './components/Editor';

Di App.js , mari kita nyatakan status yang masing-masing akan menampung konten editor HTML, CSS, dan JavaScript.

 const [html, setHtml] = useState(''); const [css, setCss] = useState(''); const [js, setJs] = useState('');

Jika Anda ingat, kami perlu menggunakan status ini untuk menyimpan dan memasok konten editor kami.

Selanjutnya, mari kita ganti tag paragraf ( p ) yang kita gunakan untuk HTML, CSS, dan JavaScript dalam rendering bersyarat dengan komponen editor yang baru saja kita buat, dan kita juga akan meneruskan prop yang sesuai ke setiap instance editor komponen:

 function App() { ... return ( <div className="App"> <p>Welcome to the edior</p> // This is where the tab buttons container is... <div className="editor-container"> { htmlEditorIsOpen ? ( <Editor language="xml" value={html} setEditorState={setHtml} /> ) : cssEditorIsOpen ? ( <Editor language="css" value={css} setEditorState={setCss} /> ) : ( <Editor language="javascript" value={js} setEditorState={setJs} /> ) } </div> </div> ); } export default App;

Jika Anda telah mengikuti sampai sekarang, Anda akan memahami apa yang kami lakukan di blok kode di atas.

Ini dia dalam bahasa Inggris yang sederhana: Kami mengganti tag p (yang ada di sana sebagai pengganti) dengan komponen editor. Kemudian, kami menyediakan props language , value , dan setEditorState , masing-masing, agar sesuai dengan statusnya.

Kami sudah sejauh ini! Inilah tampilan aplikasi kami sekarang:

Tampilan aplikasi kami sekarang
(Pratinjau besar)

Pengantar Iframe

Kita akan menggunakan inline frames (iframes) untuk menampilkan hasil dari kode yang dimasukkan dalam editor.

Menurut MDN:

Elemen HTML Inline Frame ( <iframe> ) mewakili konteks penelusuran bersarang, menyematkan halaman HTML lain ke halaman saat ini.

Bagaimana Iframe Bekerja di React

Iframe biasanya digunakan dengan HTML biasa. Menggunakan Iframes dengan React tidak memerlukan banyak perubahan, yang utama adalah mengubah nama atribut menjadi camelcase. Contohnya adalah bahwa srcdoc akan menjadi srcDoc .

Masa Depan Iframe di Web

Iframe terus menjadi sangat berguna dalam pengembangan web. Sesuatu yang mungkin ingin Anda periksa adalah Portal. Seperti yang dijelaskan Daniel Brain:

“Portal memperkenalkan serangkaian kemampuan baru yang kuat ke dalam campuran ini. Sekarang mungkin untuk membangun sesuatu yang terasa seperti iframe, yang dapat dengan mulus menganimasikan dan berubah dan mengambil alih jendela browser penuh.”

Salah satu hal yang coba dipecahkan oleh Portal adalah masalah bilah URL. Saat menggunakan iframe, komponen yang dirender di iframe tidak membawa URL unik di bilah alamat; dengan demikian, ini mungkin tidak bagus untuk pengalaman pengguna, tergantung pada kasus penggunaan. Portal layak untuk dicoba, dan saya sarankan Anda melakukannya, tetapi karena itu bukan fokus artikel kami, hanya ini yang akan saya katakan di sini.

Membuat Iframe untuk Menampung Hasil Kami

Mari kita lanjutkan tutorial kita dengan membuat iframe untuk menampung hasil editor kita.

 return ( <div className="App"> // ... <div> <iframe srcDoc={srcDoc} title="output" sandbox="allow-scripts" frameBorder="1" width="100%" height="100%" /> </div> </div> );

Di sini, kami membuat iframe dan menyimpannya di tag wadah div . Di iframe, kami melewati beberapa atribut yang kami butuhkan:

  • srcDoc
    Atribut srcDoc ditulis dalam camelcase karena ini adalah cara menulis atribut iframe di React. Saat menggunakan iframe, kita dapat menyematkan halaman web eksternal pada halaman atau merender konten HTML tertentu. Untuk memuat dan menyematkan halaman eksternal, kita akan menggunakan properti src sebagai gantinya. Dalam kasus kami, kami tidak memuat halaman eksternal; alih-alih, kami ingin membuat dokumen HTML internal baru yang menampung hasil kami; untuk ini, kita memerlukan atribut srcDoc . Atribut ini mengambil dokumen HTML yang ingin kita sematkan (kita belum membuatnya, tapi akan segera kita buat).
  • title
    Atribut title digunakan untuk mendeskripsikan isi dari inline frame.
  • sandbox
    Properti ini memiliki banyak tujuan. Dalam kasus kami, kami menggunakannya untuk mengizinkan skrip berjalan di iframe kami dengan nilai allow-scripts . Karena kami bekerja dengan editor JavaScript, ini akan berguna dengan cepat.
  • frameBorder
    Ini hanya mendefinisikan ketebalan batas iframe.
  • width dan height
    Ini mendefinisikan lebar dan tinggi iframe.

Istilah-istilah ini sekarang seharusnya lebih masuk akal bagi Anda. Mari kita lanjutkan dan mendeklarasikan status yang akan menampung dokumen template HTML untuk srcDoc . Jika Anda melihat lebih dekat pada blok kode di atas, Anda akan melihat bahwa kami memberikan nilai ke atribut srcDoc : srcDoc ={srcDoc} . Mari gunakan useState() React kita untuk mendeklarasikan status srcDoc . Untuk melakukan ini, di file App.js , buka tempat kami mendefinisikan status lainnya dan tambahkan yang ini:

 const [srcDoc, setSrcDoc] = useState(` `);

Sekarang setelah kita membuat status, hal selanjutnya yang harus dilakukan adalah menampilkan hasilnya dalam status setiap kali kita mengetik di editor kode. Tetapi yang tidak kami inginkan adalah merender ulang komponen pada setiap penekanan tombol. Dengan mengingat hal itu, mari kita lanjutkan.

Mengonfigurasi Iframe untuk Menampilkan Hasil

Setiap kali ada perubahan di salah satu editor untuk HTML, CSS, dan JavaScript, kami ingin useEffect() dipicu, dan itu akan membuat hasil yang diperbarui di iframe. Mari kita tulis useEffect() untuk melakukan ini di file App.js :

Pertama, impor kait useEffect() :

 import React, { useState, useEffect } from 'react';

Mari kita tulis useEffect() seperti ini:

 useEffect(() => { const timeOut = setTimeout(() => { setSrcDoc( ` <html> <body>${html}</body> <style>${css}</style> <script>${js}</script> </html> ` ) }, 250); return () => clearTimeout(timeOut) }, [html, css, js])

Di sini, kami menulis kait useEffect() yang akan selalu berjalan setiap kali nilai menyatakan yang kami nyatakan untuk editor HTML, CSS, dan JavaScript diubah atau diperbarui.

Mengapa kita perlu menggunakan setTimeout() ? Nah, jika kami menulis ini tanpa itu, maka setiap kali satu tombol ditekan di editor, iframe kami akan diperbarui, dan itu tidak bagus untuk kinerja secara umum. Jadi kami menggunakan setTimeout() untuk menunda pembaruan selama 250 milidetik, memberi kami cukup waktu untuk mengetahui apakah pengguna masih mengetik. Artinya, setiap kali pengguna menekan tombol, hitungan akan dimulai ulang, sehingga iframe hanya akan diperbarui ketika pengguna dalam keadaan diam (tidak mengetik) selama 250 milidetik. Ini adalah cara yang keren untuk menghindari keharusan memperbarui iframe setiap kali tombol ditekan.

Hal berikutnya yang kami lakukan di atas adalah memperbarui srcDoc dengan perubahan baru. Komponen srcDoc , seperti yang kami jelaskan di atas, merender konten HTML tertentu di iframe. Dalam kode kami, kami melewati template HTML, mengambil status html yang berisi kode yang telah diketik pengguna ke dalam editor HTML dan menempatkannya di antara tag body template kami. Kami juga mengambil status css yang berisi gaya yang diketik pengguna di editor CSS, dan kami meneruskannya di antara tag style . Terakhir, kami mengambil status js yang berisi kode JavaScript yang telah diketik pengguna di editor JavaScript, dan kami meneruskannya di antara tag script .

Perhatikan bahwa dalam menyetel setSrcDoc , kita menggunakan backticks ( ` ` ) alih-alih tanda kutip normal ( ' ' ). Ini karena backticks memungkinkan kita untuk meneruskan nilai status yang sesuai, seperti yang kita lakukan pada kode di atas.

Pernyataan return di kait useEffect() adalah fungsi pembersihan yang menghapus setTimeout() saat selesai, untuk menghindari kebocoran memori. Dokumentasi memiliki lebih banyak tentang useEffect .

Inilah yang tampak seperti proyek kami saat ini:

Seperti apa proyek kami saat ini
(Pratinjau besar)

Addons CodeMirror

Dengan add-on CodeMirror, kami dapat meningkatkan editor kami dengan lebih banyak fungsi yang akan kami temukan di editor kode lainnya. Mari kita telusuri contoh tag penutup yang ditambahkan secara otomatis saat tag pembuka diketik, dan contoh lain dari tanda kurung tutup secara otomatis saat tanda kurung buka dimasukkan:

Hal pertama yang harus dilakukan adalah mengimpor addon untuk ini ke file App.js kami:

 import 'codemirror/addon/edit/closetag'; import 'codemirror/addon/edit/closebrackets';

Mari kita berikan dalam opsi ControlledEditorComponent :

 <ControlledEditorComponent ... options={{ ... autoCloseTags: true, autoCloseBrackets: true, }} />

Sekarang inilah yang kita miliki:

Cara proyek kami terlihat
(Pratinjau besar)

Anda dapat menambahkan satu ton add-on ini ke editor Anda untuk memberikan fitur yang lebih kaya. Kami tidak mungkin melewati semuanya di sini.

Sekarang setelah kita selesai dengan ini, mari kita bahas secara singkat hal-hal yang dapat kita lakukan untuk meningkatkan aksesibilitas dan kinerja aplikasi kita.

Performa dan Aksesibilitas Solusi

Melihat editor kode web kami, beberapa hal pasti dapat diperbaiki.

Karena kami lebih memperhatikan fungsionalitas, kami mungkin sedikit mengabaikan desain. Untuk aksesibilitas yang lebih baik, berikut adalah beberapa hal yang dapat Anda lakukan untuk meningkatkan solusi ini:

  1. Anda dapat mengatur kelas active pada tombol untuk editor yang sedang terbuka. Menyoroti tombol akan meningkatkan aksesibilitas dengan memberi pengguna indikasi yang jelas tentang editor mana yang sedang mereka kerjakan.
  2. Anda mungkin ingin editor menempati lebih banyak ruang layar daripada yang kami miliki di sini. Hal lain yang dapat Anda coba adalah membuat iframe muncul dengan mengklik tombol yang ditambatkan di suatu tempat ke samping. Melakukannya akan memberi editor lebih banyak ruang layar.
  3. Editor semacam ini akan berguna bagi orang yang ingin menjalankan latihan cepat di perangkat seluler mereka, jadi perlu menyesuaikan sepenuhnya dengan seluler (belum lagi kedua poin tentang seluler di atas).
  4. Saat ini, kami dapat mengganti tema komponen editor dari beberapa tema yang kami muat, tetapi tema umum halaman tetap sama. Anda dapat mengaktifkan pengguna untuk beralih antara tema gelap dan terang untuk seluruh tata letak. Ini akan bagus untuk aksesibilitas, menghilangkan ketegangan pada mata orang karena melihat layar yang terang terlalu lama.
  5. Kami tidak melihat masalah keamanan dengan iframe kami, terutama karena kami memuat dokumen HTML internal di iframe, bukan dokumen eksternal. Jadi kita tidak perlu mempertimbangkan ini terlalu hati-hati karena iframe sangat cocok untuk use case kita.
  6. Dengan iframe, pertimbangan lain adalah waktu pemuatan halaman, karena konten yang dimuat di iframe biasanya berada di luar kendali Anda. Di aplikasi kami, ini bukan masalah karena konten iframe kami tidak eksternal.

Performa dan aksesibilitas sangat penting untuk dipertimbangkan saat Anda membangun aplikasi apa pun karena keduanya akan menentukan seberapa berguna dan dapat digunakannya aplikasi Anda bagi penggunanya.

Shedrack telah melakukan pekerjaan yang baik dalam menjelaskan metode untuk meningkatkan dan mengoptimalkan kinerja di aplikasi React. Layak untuk dicoba!

Kesimpulan

Bekerja melalui proyek yang berbeda membantu kita untuk belajar tentang berbagai mata pelajaran. Sekarang setelah Anda membaca artikel ini, jangan ragu untuk memperluas pengalaman Anda dengan bereksperimen dengan lebih banyak add-on untuk membuat editor kode lebih kaya, memperbarui UI, dan memperbaiki masalah aksesibilitas dan kinerja yang diuraikan di atas.

  • Seluruh basis kode untuk proyek ini tersedia di GitHub.

Berikut demo di Codesandbox:

Tautan dan Materi

  • “Portal Google Chrome: Seperti Iframe, Tapi Lebih Baik, dan Lebih Buruk”, Daniel Brain
  • “Mengoptimalkan Kinerja”, Bereaksi dokumentasi
  • “Manual Pengguna dan Panduan Referensi”, dokumentasi CodeMirror