Bir Web Kodu Düzenleyicisi Oluşturma

Yayınlanan: 2022-03-10
Kısa özet ↬ Şu veya bu şekilde bir kod düzenleyici gerektiren bir platform oluşturmayı düşünen bir geliştiriciyseniz, bu makale tam size göre. Bu makale, bazı HTML, CSS ve JavaScript yardımıyla sonucu gerçek zamanlı olarak görüntüleyen bir web kodu düzenleyicisinin nasıl oluşturulacağını açıklar.

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

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

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 ve onClick . Burada title bir metin dizisi olacaktır ve onClick , 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çin style 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 bir className taşır.
  • Ardından, Button bileşeninin üç örneğini açıkladık. Hatırlarsanız, Button bileşeni title ve onClick 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 alan onTabClick 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:

Şu anda sahip olduğumuz sekme geçişini gösteren bir GIF.
Şu anda sahip olduğumuz sekme geçişini gösteren bir GIF. (Büyük önizleme)

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

Ekranını esnek hale getirmek için CSS kullanıyoruz
(Büyük önizleme)

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 onu ControlledEditorComponent 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üş ifadesinde className ile boş bir div 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:

  1. XML: Bu mod HTML içindir. XML terimini kullanır.
  2. JavaScript: Bu ( codemirror/mode/javascript/javascript ) JavaScript modunu getirir.
  3. 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ğunuz onChange 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ğlanan language 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:

Uygulamamızın şimdiki görünümü
(Büyük önizleme)

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 yerine src ö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çin srcDoc ö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'imizde allow-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 ve height
    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:

Şu anda projemiz nasıl görünüyor
(Büyük önizleme)

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:

Projemizin görünüşü
(Büyük önizleme)

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:

  1. Ş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.
  2. 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.
  3. 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).
  4. Ş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.
  5. 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.
  6. 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