Bir Web Kodu Düzenleyicisi Oluşturma
Yayınlanan: 2022-03-10Çevrimiçi bir web kodu düzenleyicisi, bir kod düzenleyici uygulamasını kullanma fırsatınız olmadığında veya bilgisayarınız veya hatta cep telefonunuzla web'de hızlı bir şekilde bir şeyler denemek istediğinizde en kullanışlıdır. Bu aynı zamanda üzerinde çalışılacak ilginç bir proje çünkü bir kod düzenleyicinin nasıl oluşturulacağına dair bilgi sahibi olmak, bazı işlevleri göstermek için bir kod düzenleyiciyi entegre etmenizi gerektiren diğer projelere nasıl yaklaşacağınız konusunda size fikir verecektir.
Bu makalede takip etmek için bilmeniz gereken birkaç React kavramı:
- kancalar,
- Bileşen yapısı,
- Fonksiyonel bileşenler,
- Aksesuarlar.
CodeMirror'ı Kullanma
Editörümüzü oluşturmak için CodeMirror adlı bir kitaplık kullanacağız. CodeMirror, tarayıcı için JavaScript'te uygulanan çok yönlü bir metin düzenleyicidir. Özellikle kod düzenleme içindir ve daha gelişmiş düzenleme işlevleri için bir dizi dil modu ve eklentiyle birlikte gelir.
CodeMirror'ı uygulamanıza uyacak şekilde özelleştirmek ve yeni işlevlerle genişletmek için zengin bir programlama API'si ve bir CSS tema sistemi mevcuttur. Bize web üzerinde çalışan ve kodumuzun sonucunu gerçek zamanlı olarak gösteren zengin bir kod düzenleyicisi oluşturma işlevselliği sağlar.
Bir sonraki bölümde yeni React projemizi kuracağız ve web uygulamamızı oluşturmak için ihtiyacımız olan kütüphaneleri kuracağız.
Yeni Bir React Projesi Oluşturma
Yeni bir React projesi oluşturarak başlayalım. Komut satırı arayüzünüzde, projenizi oluşturmak istediğiniz dizine gidin ve bir React uygulaması oluşturalım ve onu code_editor
olarak adlandıralım:
npx create-react-app code_editor
Yeni React uygulamamızı oluşturduktan sonra, komut satırı arayüzünde o projenin dizinine gidelim:
cd code_editor
Burada kurmamız gereken iki kitaplık var: codemirror
ve react-codemirror2
.
npm install codemirror react-codemirror2
Bu proje için ihtiyacımız olan kütüphaneleri kurduktan sonra, sekmelerimizi oluşturalım ve editörümüzde görünecek olan üç sekme (HTML, CSS ve JavaScript için) arasında sekme geçişini etkinleştirelim.
Düğme Bileşeni
Tek tek düğmeler oluşturmak yerine düğmeyi yeniden kullanılabilir bir bileşen haline getirelim. Projemizde, ihtiyacımız olan üç sekmeye göre düğmenin üç örneği olacaktır.
src
klasöründe components
adında bir klasör oluşturun. Bu yeni components
klasöründe Button.jsx adlı bir Button.jsx
dosyası oluşturun.
Button
bileşeninde gereken tüm kodlar şunlardır:
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
İşte yukarıda yaptığımızın tam bir açıklaması:
-
Button
adında bir işlevsel bileşen oluşturduk ve daha sonra dışa aktardık. - Bileşene gelen aksesuarlardan
title
veonClick
. Buradatitle
bir metin dizisi olacaktır veonClick
, bir düğmeye tıklandığında çağrılan bir işlev olacaktır. - Daha sonra, düğmemizi bildirmek için
button
öğesini kullandık ve şık görünmek için düğmemize stil vermek içinstyle
niteliklerini kullandık. -
onClick
özniteliğini ekledik ve ona tahrip edilmişonClick
işlevi donanımlarımızı ilettik. - Bu bileşende farkedeceğiniz son şey,
button
etiketinin içeriği olarak{title}
iletilmesidir. Bu, çağrıldığında button bileşeninin örneğine hangi prop'un iletildiğine bağlı olarak başlığı dinamik olarak görüntülememizi sağlar.
Artık yeniden kullanılabilir bir düğme bileşeni oluşturduğumuza göre, devam edelim ve bileşenimizi App.js.
. App.js
gidin ve yeni oluşturulan düğme bileşenini içe aktarın:
import Button from './components/Button';
Hangi sekmenin veya düzenleyicinin açık olduğunu izlemek için, açık olan düzenleyicinin değerini tutacak bir beyan durumuna ihtiyacımız var. useState
React kancasını kullanarak, o sekmenin düğmesine tıklandığında o anda açık olan düzenleyici sekmesinin adını saklayacak durumu ayarlayacağız.
Bunu şu şekilde yapıyoruz:
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;
Burada devletimizi ilan ettik. Şu anda açık olan editörün adını alır. html
değeri, durumun varsayılan değeri olarak iletildiğinden, HTML düzenleyicisi varsayılan olarak açık olan sekme olacaktır.
Devam edelim ve bir sekme düğmesine tıklandığında durumun değerini değiştirmek için setOpenedEditor
kullanacak işlevi yazalım.
Not: İki sekme aynı anda açık olmayabilir, bu yüzden fonksiyonumuzu yazarken bunu dikkate almamız gerekecek.
onTabClick
adlı fonksiyonumuz şöyle görünür:
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;
Burada, seçili olan sekmenin adı olan tek bir işlev argümanı ilettik. Bu argüman, fonksiyonun çağrıldığı her yerde sağlanır ve o sekmenin ilgili adı iletilir.
İhtiyacımız olan üç sekme için Button
üç örneğini oluşturalım:
<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>
İşte yaptığımız şey:
- Temel olarak uygulamamızın ne hakkında olduğuna dair bir bağlam vermek için bir
p
etiketi ekleyerek başladık. - Sekme düğmelerimizi sarmak için bir
div
etiketi kullandık.div
etiketi, bu öğreticide daha sonra CSS dosyasında düğmeleri bir ızgara görünümünde stillendirmek için kullanacağımız birclassName
taşır. - Ardından,
Button
bileşeninin üç örneğini açıkladık. Hatırlarsanız,Button
bileşenititle
veonClick
olmak üzere iki sahne alır.Button
bileşeninin her örneğinde bu iki sahne sağlanır. -
title
prop, sekmenin başlığını alır. -
onClick
prop, az önce oluşturduğumuz ve tek bir argüman alanonTabClick
işlevini alır: seçilen sekmenin adı.
Seçili olan sekmeye bağlı olarak, sekmeyi koşullu olarak görüntülemek için JavaScript üçlü operatörünü kullanırdık. Bu, eğer openedEditor
durumunun değeri html
olarak ayarlanmışsa (yani setOpenedEditor('html')
), HTML bölümü sekmesinin o anda görünen sekme olacağı anlamına gelir. Aşağıda yaptığımız gibi bunu daha iyi anlayacaksınız:
... 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> ); ...
Yukarıdaki kodu sade İngilizce olarak gözden geçirelim. openedEditor
değeri html
ise, HTML bölümünü görüntüleyin. Aksi takdirde, openedEditor
değeri css
ise, CSS bölümünü görüntüleyin. Aksi takdirde, değer ne html
ne de css
ise, o zaman bu, değerin js
olması gerektiği anlamına gelir, çünkü openedEditor
durumu için yalnızca üç olası değere sahibiz; bu nedenle, JavaScript sekmesini görüntülerdik.
Üçlü operatör koşullarında farklı bölümler için paragraf etiketleri ( p
) kullandık. Devam ederken, editör bileşenlerini oluşturacağız ve p
etiketlerini editör bileşenlerinin kendileri ile değiştireceğiz.
Şimdiye kadar çoktan geldik! Bir düğme tıklandığında, temsil ettiği sekmeyi true
olarak ayarlayan eylemi başlatır ve bu sekmeyi görünür hale getirir. Uygulamamız şu anda şöyle görünüyor:
Düğmeleri tutan div
kapsayıcısına biraz CSS ekleyelim. Düğmelerin yukarıdaki resimde olduğu gibi dikey olarak yığılması yerine bir ızgarada görüntülenmesini istiyoruz. App.css
dosyanıza gidin ve aşağıdaki kodu ekleyin:
.tab-button-container{ display: flex; }
Üç sekmeli düğmeleri tutan div
etiketinde bir öznitelik olarak className="tab-button-container"
eklediğimizi hatırlayın. Burada, görüntüsünü flex
olarak ayarlamak için CSS kullanarak bu kapsayıcının stilini belirledik. Bu sonuç:
Bu noktaya gelmek için ne kadar çok şey yaptığınızla gurur duyun. Bir sonraki bölümde, p
etiketlerini onlarla değiştirerek editörlerimizi oluşturacağız.
Editörleri Oluşturma
CodeMirror düzenleyicimizde üzerinde çalışacağımız kitaplıkları zaten kurduğumuz için, devam edelim ve components
klasöründe Editor.jsx
dosyamızı oluşturalım.
bileşenler > Editor.jsx
Yeni dosyamızı oluşturduktan sonra içine bir miktar başlangıç kodu yazalım:
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
İşte yaptığımız:
-
useState
kancasıyla birlikte içe aktardık çünkü buna ihtiyacımız olacak. - CodeMirror CSS dosyasını içe aktardık (yüklediğimiz CodeMirror kitaplığından gelir, bu nedenle herhangi bir özel şekilde yüklemeniz gerekmez).
-
Controlled
react-codemirror2
içe aktardık ve daha net hale getirmek için onuControlledEditorComponent
olarak yeniden adlandırdık. Bunu kısa süre içinde kullanacağız. - Ardından,
Editor
fonksiyonel bileşenimizi ilan ettik ve şimdilik dönüş ifadesindeclassName
ile boş birdiv
içeren bir return ifademiz var.
İşlevsel bileşenimizde, language
, value
ve setEditorState
dahil olmak üzere aksesuarlardan bazı değerlerin yapısını bozduk. Bu üç destek, App.js
çağrıldığında editörün herhangi bir örneğinde sağlanır.
Editörümüzün kodunu yazmak için ControlledEditorComponent
kullanalım. İşte yapacağımız şey:
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
Bazı CodeMirror terimlerini açıklayarak burada yaptıklarımızı gözden geçirelim.
CodeMirror modları, bir düzenleyicinin hangi dili amaçladığını belirtir. Bu proje için üç düzenleyicimiz olduğu için üç modu içe aktardık:
- XML: Bu mod HTML içindir. XML terimini kullanır.
- JavaScript: Bu (
codemirror/mode/javascript/javascript
) JavaScript modunu getirir. - CSS: Bu (
codemirror/mode/css/css
) CSS modunu getirir.
Not: Düzenleyici, yeniden kullanılabilir bir bileşen olarak oluşturulduğundan, düzenleyiciye doğrudan bir mod koyamayız. Böylece modu, yapısını bozduğumuz language
propu üzerinden sağlıyoruz. Ancak bu, çalışmak için modların içe aktarılması gerektiği gerçeğini değiştirmez.
Ardından, ControlledEditorComponent
içindeki şeyleri tartışalım:
-
onBeforeChange
Bu, düzenleyiciye yazdığınızda veya editörden kaldırdığınızda çağrılır. Bunu, değişiklikleri izlemek için normalde bir giriş alanında sahip olduğunuzonChange
işleyicisi gibi düşünün. Bunu kullanarak, yeni bir değişiklik olduğunda editörümüzün değerini alabileceğiz ve editörümüzün durumuna kaydedebileceğiz. Devam ederken{handleChange}
fonksiyonunu yazacağız. -
value = {value}
Bu, herhangi bir zamanda editörün içeriğidir. Bu özniteliğe,value
adında, yapısı bozulmuş bir pervane ilettik.value
props, o düzenleyicinin değerini tutan durumdur. Bu, editörün örneğinden sağlanacaktır. -
className
="code-mirror-wrapper"
Bu sınıf ismi bizim kendi yaptığımız bir tarz değil. Yukarıda içe aktardığımız CodeMirror'ın CSS dosyasından sağlanır. -
options
Bu, düzenleyicimizin sahip olmasını istediğimiz farklı işlevleri alan bir nesnedir. CodeMirror'da birçok harika seçenek var. Burada kullandıklarımıza bakalım:-
lineWrapping: true
Bu, satır dolduğunda kodun bir sonraki satıra kaydırılması gerektiği anlamına gelir. -
lint: true
Bu linting sağlar. -
mode: language
Bu mod, yukarıda tartışıldığı gibi, editörün kullanılacağı dili alır. Dil yukarıda zaten içe aktarıldı, ancak editör, prop aracılığıyla editöre sağlananlanguage
değerine dayalı bir dil uygulayacak. -
lineNumbers: true
Bu, editörün her satır için satır numaralarına sahip olması gerektiğini belirtir.
-
Ardından, onBeforeChange
işleyicisi için handleChange
işlevini yazabiliriz:
const handleChange = (editor, data, value) => { setEditorState(value); }
onBeforeChange
işleyicisi bize üç şeye erişim sağlar: editor, data, value
.
Sadece value
ihtiyacımız var çünkü setEditorState
iletmek istediğimiz şey bu. setEditorState
prop, App.js
bildirdiğimiz her durum için ayar değerini temsil eder ve her düzenleyicinin değerini tutar. Devam ederken, bunu bir prop olarak Editor
bileşenine nasıl geçireceğimize bakacağız.
Ardından, editör için farklı temalar seçmemize izin veren bir açılır menü ekleyeceğiz. Öyleyse CodeMirror'daki temalara bakalım.
CodeMirror Temaları
CodeMirror, aralarından seçim yapabileceğimiz birden fazla temaya sahiptir. Mevcut farklı temaların demolarını görmek için resmi web sitesini ziyaret edin. Kullanıcının editörümüzden seçebileceği farklı temalar içeren bir açılır menü yapalım. Bu eğitim için beş tema ekleyeceğiz, ancak istediğiniz kadar ekleyebilirsiniz.
İlk olarak, temalarımızı Editor.js
bileşenine aktaralım:
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';
Ardından, içe aktardığımız tüm temaların bir dizisini oluşturun:
const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night']
Seçilen temanın değerini tutmak için bir useState
kancası tanımlayalım ve varsayılan temayı dracula
olarak ayarlayalım:
const [theme, setTheme] = useState("dracula")
Açılır menüyü oluşturalım:
... 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> ) ...
Yukarıdaki kodda, açılır listemize bir etiket eklemek için label
HTML etiketini kullandık ve ardından açılır listemizi oluşturmak için select
HTML etiketini ekledik. select
öğesindeki option
etiketi, açılır menüde bulunan seçenekleri tanımlar.
Açılır menüyü oluşturduğumuz themeArray
tema adlarıyla doldurmamız gerektiğinden, themeArray
eşlemek için .map
dizi yöntemini kullandık ve option
etiketini kullanarak adları tek tek görüntülemek için kullandık.
Bekleyin - yukarıdaki kodu açıklamadık. Açılış select
etiketinde, açılır menüde yeni bir değer seçildiğinde theme
durumunu izlemek ve güncellemek için onChange
özniteliğini geçtik. Açılır menüde yeni bir seçenek seçildiğinde, bize döndürülen nesneden değer alınır. Ardından, yeni değeri durumun sahip olduğu değer olarak ayarlamak için durum setTheme
kullanırız.
Bu noktada açılır listemizi oluşturduk, temamızın durumunu kurduk ve durumu yeni değerle ayarlamak için fonksiyonumuzu yazdık. CodeMirror'un temamızı kullanmasını sağlamak için yapmamız gereken son şey, temayı ControlledEditorComponent
içindeki options
nesnesine geçirmek. options
nesnesinde, theme
adında bir değer ekleyelim ve bu değeri, aynı zamanda theme
olarak adlandırılan seçili tema için durumun değerine ayarlayalım.
ControlledEditorComponent
şimdi şöyle görünür:
<ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }} />
Şimdi, editörde seçilebilecek farklı temaların bir açılır listesini yaptık.
Editor.js
kodun tamamı şu anda şöyle görünür:
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
Stil vermemiz gereken tek bir className
var. App.css
gidin ve aşağıdaki stili ekleyin:
.editor-container{ padding-top: 0.4%; }
Editörlerimiz hazır olduğuna göre, şimdi App.js
geri dönelim ve onları orada kullanalım.
kaynak > App.js
Yapmamız gereken ilk şey, Editor.js
bileşenini buraya aktarmak:
import Editor from './components/Editor';
App.js
sırasıyla HTML, CSS ve JavaScript editörlerinin içeriklerini tutacak durumları bildirelim.
const [html, setHtml] = useState(''); const [css, setCss] = useState(''); const [js, setJs] = useState('');
Hatırlarsanız, editörlerimizin içeriklerini tutmak ve tedarik etmek için bu durumları kullanmamız gerekecek.
Ardından, koşullu oluşturmalarda HTML, CSS ve JavaScript için kullandığımız paragraf ( p
) etiketlerini yeni oluşturduğumuz düzenleyici bileşenleriyle değiştirelim ve ayrıca düzenleyicinin her örneğine uygun prop'u iletelim. bileşen:
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;
Şimdiye kadar takip ettiyseniz, yukarıdaki kod bloğunda ne yaptığımızı anlayacaksınız.
İşte sade İngilizce: (yer tutucular olarak orada bulunan) p
etiketlerini editör bileşenlerinin örnekleriyle değiştirdik. Ardından, karşılık gelen durumlarıyla eşleşmeleri için sırasıyla language
, value
ve setEditorState
sağladık.
Şimdiye kadar geldik! Uygulamamız şu anda böyle görünüyor:
Iframe'lere Giriş
Düzenleyiciye girilen kodun sonucunu görüntülemek için satır içi çerçevelerden (iframe'ler) yararlanacağız.
MDN'ye göre:
HTML Satır İçi Çerçeve öğesi (
<iframe>
), geçerli sayfaya başka bir HTML sayfası gömerek iç içe gözatma bağlamını temsil eder.
Iframe'ler React'te Nasıl Çalışır?
Iframe'ler normalde düz HTML ile kullanılır. Iframe'leri React ile kullanmak çok fazla değişiklik gerektirmez, en önemlisi öznitelik adlarını camelcase'e dönüştürmektir. Bunun bir örneği, srcdoc
haline srcDoc
.
Web'de Iframe'lerin Geleceği
Iframe'ler web geliştirmede gerçekten faydalı olmaya devam ediyor. Kontrol etmek isteyebileceğiniz bir şey Portallar. Daniel Brain'in açıkladığı gibi:
“Portallar, bu karışıma yeni ve güçlü bir dizi yetenek katıyor. Artık, iframe gibi hissettiren, sorunsuz bir şekilde canlandırabilen, dönüşebilen ve tüm tarayıcı penceresini devralabilen bir şey oluşturmak mümkün.”
Portalların çözmeye çalıştığı şeylerden biri de URL çubuğu sorunudur. iframe kullanılırken, iframe'de oluşturulan bileşenler adres çubuğunda benzersiz bir URL taşımaz; bu nedenle, kullanım durumuna bağlı olarak bu, kullanıcı deneyimi için harika olmayabilir. Portallar göz atmaya değer ve bunu yapmanızı öneririm, ancak makalemizin odak noktası olmadığı için burada onun hakkında söyleyeceğim tek şey bu.
Sonucumuzu Barındıracak Iframe Oluşturma
Editörlerimizin sonucunu barındıracak bir iframe oluşturarak öğreticimizle devam edelim.
return ( <div className="App"> // ... <div> <iframe srcDoc={srcDoc} title="output" sandbox="allow-scripts" frameBorder="1" width="100%" height="100%" /> </div> </div> );
Burada iframe'i oluşturduk ve onu bir div
kapsayıcı etiketine yerleştirdik. iframe'de, ihtiyacımız olan bazı özellikleri ilettik:
-
srcDoc
srcDoc
iframe öznitelikleri bu şekilde yazıldığı için srcDoc özniteliği camelcase'de yazılmıştır. Bir iframe kullanırken, sayfaya harici bir web sayfası yerleştirebilir veya belirtilen HTML içeriğini oluşturabiliriz. Harici bir sayfa yüklemek ve gömmek için bunun yerinesrc
özelliğini kullanırdık. Bizim durumumuzda, harici bir sayfa yüklemiyoruz; bunun yerine, sonucumuzu barındıran yeni bir dahili HTML belgesi oluşturmak istiyoruz; bunun içinsrcDoc
özniteliğine ihtiyacımız var. Bu öznitelik, gömmek istediğimiz HTML belgesini alır (bunu henüz oluşturmadık, ama yakında yapacağız). -
title
Başlık özelliği, satır içi çerçevenin içeriğini tanımlamak için kullanılır. -
sandbox
Bu mülkün birçok amacı vardır. Bizim durumumuzda, komut dosyalarının iframe'imizdeallow-scripts
değeriyle çalışmasına izin vermek için kullanıyoruz. Bir JavaScript düzenleyicisi ile çalıştığımız için, bu hızlı bir şekilde kullanışlı olacaktır. -
frameBorder
Bu sadece iframe'in kenarlık kalınlığını tanımlar. -
width
veheight
Bu, iframe'in genişliğini ve yüksekliğini tanımlar.
Bu terimler şimdi size daha anlamlı gelmelidir. Devam edelim ve srcDoc
için HTML şablon belgesini tutacak durumu bildirelim. Yukarıdaki kod bloğuna yakından bakarsanız, srcDoc
niteliğine bir değer ilettiğimizi görürsünüz: srcDoc
={srcDoc}
. srcDoc
durumunu bildirmek için useState()
React kancamızı kullanalım. Bunun için App.js
dosyasında diğer durumları tanımladığımız yere gidin ve şunu ekleyin:
const [srcDoc, setSrcDoc] = useState(` `);
Artık durumu oluşturduğumuza göre, bundan sonraki yapacağımız şey, kod düzenleyicisine her yazdığımızda sonucu durumda görüntülemektir. Ancak istemediğimiz şey, her bir tuşa basışta bileşeni yeniden oluşturmaktır. Bunu göz önünde bulundurarak devam edelim.
Sonucu Görüntülemek için Iframe'i Yapılandırma
Sırasıyla HTML, CSS ve JavaScript düzenleyicilerinden herhangi birinde bir değişiklik olduğunda, useEffect()
tetiklenmesini istiyoruz ve bu, iframe'de güncellenmiş sonucu oluşturacaktır. Bunu yapmak için App.js
dosyasına useEffect()
yazalım:
İlk önce useEffect()
kancasını içe aktarın:
import React, { useState, useEffect } from 'react';
useEffect()
'i şöyle yazalım:
useEffect(() => { const timeOut = setTimeout(() => { setSrcDoc( ` <html> <body>${html}</body> <style>${css}</style> <script>${js}</script> </html> ` ) }, 250); return () => clearTimeout(timeOut) }, [html, css, js])
Burada, HTML, CSS ve JavaScript düzenleyicileri için bildirdiğimiz değer durumları değiştirildiğinde veya güncellendiğinde her zaman çalışacak bir useEffect()
kancası yazdık.
Neden setTimeout()
kullanmamız gerekti? Pekala, bunu onsuz yazsaydık, o zaman bir düzenleyicide tek bir tuşa her basıldığında, iframe'imiz güncellenir ve bu genel olarak performans için pek iyi değildir. Bu yüzden güncellemeyi 250 milisaniye geciktirmek için setTimeout()
kullanıyoruz, bu da kullanıcının hala yazıp yazmadığını anlamamız için bize yeterli zaman veriyor. Yani, kullanıcı bir tuşa her bastığında sayımı yeniden başlatır, böylece iframe yalnızca kullanıcı 250 milisaniye boyunca boşta kaldığında (yazmıyorsa) güncellenir. Bu, bir tuşa her basıldığında iframe'i güncellemek zorunda kalmamanın harika bir yoludur.
Yukarıda yaptığımız bir sonraki şey, srcDoc
yeni değişikliklerle güncellemekti. srcDoc
bileşeni, yukarıda açıkladığımız gibi, belirtilen HTML içeriğini iframe'de işler. Kodumuzda, kullanıcının HTML düzenleyicisine yazdığı kodu içeren html
durumunu alıp şablonumuzun body
etiketleri arasına yerleştirerek bir HTML şablonu geçtik. Kullanıcının CSS editöründe yazdığı stilleri içeren css
durumunu da aldık ve bunu style
etiketleri arasında geçirdik. Son olarak kullanıcının JavaScript düzenleyicisine yazdığı JavaScript kodunu içeren js
durumunu aldık ve script
etiketleri arasına aktardık.
setSrcDoc
ayarında, normal tırnak işaretleri ( ' '
) yerine ters tırnaklar ( ` `
) kullandığımıza dikkat edin. Bunun nedeni, yukarıdaki kodda yaptığımız gibi, geri tepmelerin karşılık gelen durum değerlerini geçmemize izin vermesidir.
useEffect()
kancasındaki return
ifadesi, bellek sızıntısını önlemek için tamamlandığında setTimeout()
öğesini temizleyen bir temizleme işlevidir. Belgelerde useEffect
hakkında daha fazla bilgi var.
İşte projemiz şu anda nasıl görünüyor:
CodeMirror Eklentileri
CodeMirror eklentileri ile düzenleyicimizi, diğer kod düzenleyicilerde bulacağımız türden daha fazla işlevsellik ile geliştirebiliriz. Bir açılış etiketi yazıldığında otomatik olarak eklenen bir kapanış etiketi örneğini ve açılış ayracı girildiğinde otomatik olarak kapanan bir ayraç örneğini inceleyelim:
Yapılacak ilk şey, bunun için App.js
dosyamıza aktarmaktır:
import 'codemirror/addon/edit/closetag'; import 'codemirror/addon/edit/closebrackets';
ControlledEditorComponent
seçeneklerinde iletelim:
<ControlledEditorComponent ... options={{ ... autoCloseTags: true, autoCloseBrackets: true, }} />
Şimdi elimizde şunlar var:
Daha zengin özellikler vermek için düzenleyicinize bu eklentilerden bir ton ekleyebilirsiniz. Bunların hepsini burada geçmemiz mümkün değil.
Artık bununla işimiz bittiğinde, uygulamamızın erişilebilirliğini ve performansını iyileştirmek için yapabileceğimiz şeyleri kısaca tartışalım.
Çözümün Performansı ve Erişilebilirliği
Web kodu düzenleyicimize baktığımızda, bazı şeyler kesinlikle geliştirilebilir.
Öncelikli olarak işlevselliğe önem verdiğimiz için tasarımı biraz ihmal etmiş olabiliriz. Daha iyi erişilebilirlik için bu çözümü geliştirmek için yapabileceğiniz bazı şeyler şunlardır:
- Şu anda açık olan editör için butona
active
bir sınıf ayarlayabilirsiniz. Düğmenin vurgulanması, kullanıcılara şu anda hangi düzenleyici üzerinde çalıştıklarını net bir şekilde göstererek erişilebilirliği artıracaktır. - Editörün burada sahip olduğumuzdan daha fazla ekran alanı kaplamasını isteyebilirsiniz. Deneyebileceğiniz başka bir şey de, yan tarafta bir yere yerleştirilmiş bir düğmeyi tıklatarak iframe'in açılmasını sağlamaktır. Bunu yapmak, editöre daha fazla ekran alanı sağlayacaktır.
- Bu tür bir düzenleyici, mobil cihazlarında hızlı bir alıştırma yapmak isteyen kişiler için faydalı olacaktır, bu nedenle, onu tamamen mobil cihazlara uyarlamak gerekli olacaktır (yukarıda mobil ile ilgili her iki noktadan bahsetmiyorum bile).
- Şu anda, yüklediğimiz birden çok tema arasından düzenleyici bileşeninin temasını değiştirebiliyoruz, ancak sayfanın genel teması aynı kalıyor. Kullanıcının tüm düzen için koyu ve açık tema arasında geçiş yapmasını sağlayabilirsiniz. Bu, erişilebilirlik için iyi olur ve insanların parlak bir ekrana çok uzun süre bakmasını engelleyen göz yorgunluğunu giderir.
- Temel olarak harici bir belge yerine iframe'e dahili bir HTML belgesi yüklediğimiz için iframe'imizle ilgili güvenlik sorunlarına bakmadık. Dolayısıyla, bunu çok dikkatli bir şekilde düşünmemize gerek yok çünkü iframe'ler bizim kullanım durumumuz için çok uygun.
- iframe'lerde, iframe'e yüklenen içerik normalde kontrolünüz dışında olacağından, sayfa yükleme süresi de dikkate alınması gereken bir diğer husustur. Uygulamamızda bu bir sorun değil çünkü iframe içeriğimiz harici değil.
Herhangi bir uygulama oluştururken performans ve erişilebilirlik çok dikkate değerdir çünkü uygulamanızın kullanıcıları için ne kadar yararlı ve kullanılabilir olduğunu belirleyeceklerdir.
Shedrack, React uygulamalarında performansı iyileştirme ve optimize etme yöntemlerini açıklamakta iyi bir iş çıkardı. Kontrol etmeye değer!
Çözüm
Farklı projeler üzerinde çalışmak, geniş bir konu yelpazesi hakkında bilgi edinmemize yardımcı olur. Artık bu makaleyi gözden geçirdiğinize göre, kod düzenleyiciyi daha zengin hale getirmek için daha fazla eklenti deneyerek, kullanıcı arayüzünü yenileyerek ve yukarıda özetlenen erişilebilirlik ve performans endişelerini gidererek deneyiminizi genişletmekten çekinmeyin.
- Bu proje için tüm kod tabanı GitHub'da mevcuttur.
İşte Codesandbox'taki demo:
Bağlantılar ve Materyal
- "Google Chrome'un Portalları: Iframe'ler Gibi, Ama Daha İyi ve Daha Kötü", Daniel Brain
- "Performansı Optimize Etme", React belgeleri
- "Kullanıcı Kılavuzu ve Başvuru Kılavuzu", CodeMirror belgeleri