Webコードエディタの構築

公開: 2022-03-10
簡単な要約↬何らかの形式のコードエディタを必要とするプラットフォームの構築を考えている開発者の場合、この記事はあなたにぴったりです。 この記事では、HTML、CSS、JavaScriptを使用して結果をリアルタイムで表示するWebコードエディタを作成する方法について説明します。

オンラインWebコードエディタは、コードエディタアプリケーションを使用する機会がない場合、またはコンピュータや携帯電話でWeb上で何かをすばやく試してみたい場合に最も役立ちます。 コードエディタの構築方法に関する知識があると、一部の機能を表示するためにコードエディタを統合する必要がある他のプロジェクトにアプローチする方法についてのアイデアが得られるため、これも興味深いプロジェクトです。

この記事を続けるために知っておく必要のあるReactの概念をいくつか示します。

  • フック、
  • コンポーネント構造、
  • 機能コンポーネント、
  • 小道具。

CodeMirrorの使用

CodeMirrorという名前のライブラリを使用してエディターを構築します。 CodeMirrorは、ブラウザ用にJavaScriptで実装された用途の広いテキストエディタです。 これは特にコードの編集用であり、より高度な編集機能のための多くの言語モードとアドオンが付属しています。

豊富なプログラミングAPIとCSSテーマシステムを使用して、CodeMirrorをアプリケーションに合わせてカスタマイズし、新しい機能で拡張できます。 これにより、Web上で実行され、コードの結果をリアルタイムで表示するリッチコードエディターを作成する機能が提供されます。

次のセクションでは、新しいReactプロジェクトをセットアップし、Webアプリを構築するために必要なライブラリをインストールします。

新しいReactプロジェクトの作成

新しいReactプロジェクトを作成することから始めましょう。 コマンドラインインターフェイスで、プロジェクトを作成するディレクトリに移動し、Reactアプリケーションを作成してcode_editorという名前を付けましょう。

 npx create-react-app code_editor

新しいReactアプリケーションを作成したら、コマンドラインインターフェイスでそのプロジェクトのディレクトリに移動しましょう。

 cd code_editor

ここにインストールする必要があるライブラリは、 codemirrorreact-codemirror2 2つです。

 npm install codemirror react-codemirror2

このプロジェクトに必要なライブラリをインストールしたら、タブを作成し、エディターに表示される3つのタブ(HTML、CSS、およびJavaScriptの場合)間のタブ切り替えを有効にします。

ジャンプした後もっと! 以下を読み続けてください↓

ボタンコンポーネント

個々のボタンを作成する代わりに、ボタンを再利用可能なコンポーネントにしましょう。 私たちのプロジェクトでは、必要な3つのタブに応じて、ボタンには3つのインスタンスがあります。

srcフォルダーにcomponentsという名前のフォルダーを作成します。 この新しいcomponentsフォルダに、 Button.jsxという名前のJSXファイルを作成します。

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

上記で行ったことの完全な説明は次のとおりです。

  • Buttonという名前の機能コンポーネントを作成し、それをエクスポートしました。
  • コンポーネントに入ってくる小道具からtitleonClickを分解しました。 ここで、 titleはテキストの文字列であり、 onClickはボタンがクリックされたときに呼び出される関数です。
  • 次に、 button要素を使用してボタンを宣言し、 style属性を使用してボタンのスタイルを設定して見栄えを良くしました。
  • onClick属性を追加し、非構造化されたonClick関数の小道具をそれに渡しました。
  • このコンポーネントで最後に気付くのは、 buttonタグのコンテンツとして{title}を渡すことです。 これにより、ボタンコンポーネントが呼び出されたときに、そのインスタンスに渡されるpropに基づいて、タイトルを動的に表示できます。

再利用可能なボタンコンポーネントを作成したので、次に進んでコンポーネントをApp.js.に取り込みます。 App.jsに移動し、新しく作成されたボタンコンポーネントをインポートします。

 import Button from './components/Button';

どのタブまたはエディターが開いているかを追跡するには、開いているエディターの値を保持するための宣言状態が必要です。 useState Reactフックを使用して、タブのボタンがクリックされたときに現在開いているエディタータブの名前を格納する状態を設定します。

これが私たちのやり方です:

 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;

ここで、私たちは自分たちの状態を宣言しました。 現在開いているエディターの名前を取ります。 値htmlが状態のデフォルト値として渡されるため、HTMLエディターはデフォルトで開いているタブになります。

次に進み、 setOpenedEditorを使用して、タブボタンがクリックされたときの状態の値を変更する関数を記述します。

注: 2つのタブが同時に開いていない可能性があるため、関数を作成するときにそれを考慮する必要があります。

onTabClickという名前の関数は次のようになります。

 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;

ここでは、現在選択されているタブの名前である単一の関数引数を渡しました。 この引数は、関数が呼び出される場所であればどこでも提供され、そのタブの関連する名前が渡されます。

必要な3つのタブ用にButtonの3つのインスタンスを作成しましょう。

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

これが私たちがしたことです:

  • まず、 pタグを追加しました。これは、基本的に、アプリケーションの内容にコンテキストを与えるためです。
  • タブボタンをラップするためにdivタグを使用しました。 divタグには、このチュートリアルの後半でCSSファイルのグリッド表示にボタンのスタイルを設定するために使用するclassNameが含まれています。
  • 次に、 Buttonコンポーネントの3つのインスタンスを宣言しました。 思い出してくださいButtonコンポーネントは、 titleonClickの2つの小道具を取ります。 Buttonコンポーネントのすべてのインスタンスで、これら2つの小道具が提供されます。
  • titleプロップはタブのタイトルを取ります。
  • onClickプロパティは、作成したばかりの関数onTabClickを取ります。この関数は、選択したタブの名前という1つの引数を取ります。

現在選択されているタブに基づいて、JavaScriptの三項演算子を使用してタブを条件付きで表示します。 これは、 openedEditor状態の値がhtmlに設定されている場合(つまりsetOpenedEditor('html') )、HTMLセクションのタブが現在表示されているタブになることを意味します。 以下で行うと、これをよりよく理解できます。

 ... 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> ); ...

上記のコードを平易な英語で調べてみましょう。 openedEditorの値がhtmlの場合、HTMLセクションを表示します。 それ以外の場合、 openedEditorの値がcssの場合は、CSSセクションを表示します。 それ以外の場合、値がhtmlでもcssでもない場合、 openedEditor状態の可能な値は3つしかないため、値はjsでなければならないことを意味します。 したがって、JavaScriptのタブを表示します。

三項演算子条件のさまざまなセクションに段落タグ( p )を使用しました。 先に進むにつれて、エディターコンポーネントを作成し、 pタグをエディターコンポーネント自体に置き換えます。

もうここまで来ました! ボタンがクリックされると、それが表すタブをtrueに設定するアクションが起動され、そのタブが表示されます。 現在、アプリは次のようになっています。

現在のタブトグルを示すGIF。
現在のタブトグルを示すGIF。 (大プレビュー)

ボタンを保持しているdivコンテナに小さなCSSを追加しましょう。 上の画像のように垂直に積み重ねるのではなく、ボタンをグリッドに表示する必要があります。 App.cssファイルに移動し、次のコードを追加します。

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

3つのタブボタンを保持するdivタグの属性としてclassName="tab-button-container"を追加したことを思い出してください。 ここでは、CSSを使用してその表示をflexに設定し、そのコンテナーのスタイルを設定しました。 結果は次のとおりです。

CSSを使用して表示をフレックスに設定します
(大プレビュー)

この点に到達するためにあなたがどれだけしたかを誇りに思ってください。 次のセクションでは、エディターを作成し、 pタグをそれらに置き換えます。

エディターの作成

作業するライブラリはCodeMirrorエディタ内にすでにインストールされているので、先に進んで、 componentsフォルダにEditor.jsxファイルを作成しましょう。

コンポーネント>Editor.jsx

新しいファイルを作成したら、その中に初期コードを記述しましょう。

 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

これが私たちがしたことです:

  • 必要になるため、 useStateフックと一緒にReactをインポートしました。
  • CodeMirror CSSファイルをインポートしました(これは、インストールしたCodeMirrorライブラリからのものであるため、特別な方法でインストールする必要はありません)。
  • Controlledreact-codemirror2からインポートし、わかりやすくするために名前をControlledEditorComponentに変更しました。 これはまもなく使用します。
  • 次に、 Editor関数コンポーネントを宣言しました。ここでは、returnステートメントにclassNameが含まれ、 divが空のreturnステートメントがあります。

機能コンポーネントでは、 languagevaluesetEditorStateなど、小道具からいくつかの値を分解しました。 これらの3つの小道具は、 App.jsで呼び出されたときに、エディターの任意のインスタンスで提供されます。

ControlledEditorComponentを使用して、エディターのコードを記述しましょう。 これが私たちがすることです:

 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

ここで行ったことを見ていき、CodeMirrorの用語をいくつか説明しましょう。

CodeMirrorモードは、エディターの対象言語を指定します。 このプロジェクトには3つのエディターがあるため、3つのモードをインポートしました。

  1. XML:このモードはHTML用です。 XMLという用語を使用します。
  2. JavaScript:これ( codemirror/mode/javascript/javascript )はJavaScriptモードをもたらします。
  3. CSS:これ( codemirror/mode/css/css )はCSSモードになります。

注:エディターは再利用可能なコンポーネントとして構築されているため、エディターに直接モードを設定することはできません。 したがって、分解したlanguage小道具を介してモードを提供します。 ただし、これによって、動作するためにモードをインポートする必要があるという事実は変わりません。

次に、 ControlledEditorComponentの内容について説明しましょう。

  • onBeforeChange
    これは、エディターに書き込んだり、エディターから削除したりするたびに呼び出されます。 これは、変更を追跡するために入力フィールドに通常あるonChangeハンドラーのように考えてください。 これを使用すると、新しい変更があったときにいつでもエディターの値を取得して、エディターの状態に保存することができます。 先に進むにつれて、 {handleChange}関数を記述します。
  • value = {value}
    これは、いつでも編集者のコンテンツにすぎません。 valueという名前の非構造化プロップをこの属性に渡しました。 value propsは、そのエディターの値を保持している状態です。 これは、エディターのインスタンスから提供されます。
  • className ="code-mirror-wrapper"
    このクラス名は、私たちが自分で作成したスタイルではありません。 これは、上記でインポートしたCodeMirrorのCSSファイルから提供されます。
  • options
    これは、エディターに必要なさまざまな機能を利用するオブジェクトです。 CodeMirrorには多くのすばらしいオプションがあります。 ここで使用したものを見てみましょう:
    • lineWrapping: true
      これは、行がいっぱいになると、コードが次の行に折り返される必要があることを意味します。
    • lint: true
      これにより、リンティングが可能になります。
    • mode: language
      このモードは、前述のように、エディターが使用される言語を使用します。 言語はすでに上記でインポートされていますが、エディターは、プロップを介してエディターに提供されたlanguage値に基づいて言語を適用します。
    • lineNumbers: true
      これは、エディターが各行に行番号を持つ必要があることを指定します。

次に、 onBeforeChangeハンドラーのhandleChange関数を記述できます。

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

onBeforeChangeハンドラーを使用するとeditor, data, value 3つにアクセスできます。

値が必要なのは、 setEditorStateで渡したいvalueだからです。 setEditorState propは、 App.jsで宣言した各状態の設定値を表し、各エディターの値を保持します。 次に進むにつれて、これを小道具としてEditorコンポーネントに渡す方法を見ていきます。

次に、エディターのさまざまなテーマを選択できるドロップダウンを追加します。 それでは、CodeMirrorのテーマを見てみましょう。

CodeMirrorテーマ

CodeMirrorには、選択できる複数のテーマがあります。 公式ウェブサイトにアクセスして、利用可能なさまざまなテーマのデモを確認してください。 ユーザーがエディターで選択できるさまざまなテーマでドロップダウンを作成しましょう。 このチュートリアルでは、5つのテーマを追加しますが、いくつでも追加できます。

まず、 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';

次に、インポートしたすべてのテーマの配列を作成します。

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

選択したテーマの値を保持するuseStateフックを宣言し、デフォルトのテーマをdraculaとして設定しましょう。

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

ドロップダウンを作成しましょう:

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

上記のコードでは、 label HTMLタグを使用してドロップダウンにラベルを追加し、次にselectタグを追加してドロップダウンを作成しました。 select要素のoptionタグは、ドロップダウンで使用可能なオプションを定義します。

作成したthemeArrayのテーマ名をドロップダウンに入力する必要があるため、 .map arrayメソッドを使用してthemeArrayをマップし、 optionタグを使用して名前を個別に表示しました。

ちょっと待ってください—上記のコードの説明はまだ終わっていません。 開始selectタグで、 onChange属性を渡して、ドロップダウンで新しい値が選択されるたびにthemeの状態を追跡および更新します。 ドロップダウンで新しいオプションが選択されるたびに、返されるオブジェクトから値が取得されます。 次に、状態フックのsetThemeを使用して、新しい値を状態が保持する値に設定します。

この時点で、ドロップダウンを作成し、テーマの状態を設定し、新しい値で状態を設定する関数を記述しました。 CodeMirrorにテーマを使用させるために必要な最後のことは、 ControlledEditorComponentoptionsオブジェクトにテーマを渡すことです。 optionsオブジェクトで、 themeという名前の値を追加し、その値を、 themeという名前の選択したテーマの状態の値に設定しましょう。

ControlledEditorComponentは次のようになります。

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

これで、エディターで選択できるさまざまなテーマのドロップダウンが作成されました。

現在、 Editor.jsの完全なコードは次のようになっています。

 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

スタイルを設定する必要があるclassNameは1つだけです。 App.cssに移動し、次のスタイルを追加します。

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

編集者の準備ができたので、 App.jsに戻ってそこで使用しましょう。

src> App.js

最初に行う必要があるのは、ここにEditor.jsコンポーネントをインポートすることです。

 import Editor from './components/Editor';

App.jsで、HTML、CSS、JavaScriptエディターのコンテンツをそれぞれ保持する状態を宣言しましょう。

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

思い出してください。編集者のコンテンツを保持および提供するには、これらの状態を使用する必要があります。

次に、条件付きレンダリングでHTML、CSS、およびJavaScriptに使用した段落( p )タグを、作成したばかりのエディターコンポーネントに置き換えます。また、エディターの各インスタンスに適切なプロパティを渡します。成分:

 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;

これまでフォローしてきた場合は、上記のコードブロックで行ったことを理解できます。

ここでは平易な英語ですpタグ(プレースホルダーとして存在していた)をエディターコンポーネントのインスタンスに置き換えました。 次に、対応する状態に一致するように、それぞれlanguagevalue 、およびsetEditorStateプロップを提供しました。

ここまで来ました! これが私たちのアプリが今どのように見えるかです:

私たちのアプリが今どのように見えるか
(大プレビュー)

Iframeの紹介

インラインフレーム(iframe)を使用して、エディターに入力されたコードの結果を表示します。

MDNによると:

HTMLインラインフレーム要素( <iframe> )は、ネストされたブラウジングコンテキストを表し、現在のページに別のHTMLページを埋め込みます。

IframeがReactでどのように機能するか

Iframeは通常、プレーンHTMLで使用されます。 ReactでIframeを使用する場合、多くの変更は必要ありません。主な変更は、属性名をキャメルケースに変換することです。 この例は、 srcdocsrcDocになることです。

Web上のIframeの未来

Iframeは、引き続きWeb開発で非常に役立ちます。 あなたがチェックしたいと思うかもしれない何かはポータルです。 ダニエルブレインが説明するように:

「ポータルは、このミックスに強力な新しい機能セットを導入します。 これで、iframeのような感覚で、シームレスにアニメーション化およびモーフィングして、ブラウザウィンドウ全体を引き継ぐことができるものを構築することが可能になりました。」

ポータルが解決しようとしていることの1つは、URLバーの問題です。 iframeを使用する場合、iframeでレンダリングされたコンポーネントは、アドレスバーに一意のURLを持ちません。 そのため、ユースケースによっては、これはユーザーエクスペリエンスに適さない場合があります。 ポータルはチェックする価値があります。そうすることをお勧めしますが、これは私たちの記事の焦点では​​ないため、ここで説明するのはこれだけです。

結果を格納するためのIframeの作成

編集者の結果を格納するiframeを作成して、チュートリアルを進めましょう。

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

ここでは、iframeを作成し、 divコンテナタグに格納しました。 iframeで、必要ないくつかの属性を渡しました。

  • srcDoc
    srcDoc属性はキャメルケースで記述されています。これはReactでiframe属性を記述する方法であるためです。 iframeを使用する場合、ページに外部Webページを埋め込むか、指定したHTMLコンテンツをレンダリングできます。 外部ページを読み込んで埋め込むには、代わりにsrcプロパティを使用します。 この場合、外部ページをロードしていません。 むしろ、結果を格納する新しい内部HTMLドキュメントを作成したいと思います。 このためには、 srcDoc属性が必要です。 この属性は、埋め込みたいHTMLドキュメントを取得します(まだ作成していませんが、間もなく作成します)。
  • title
    title属性は、インラインフレームのコンテンツを説明するために使用されます。
  • sandbox
    このプロパティには多くの目的があります。 この例では、 allow-scripts値を使用してiframeでスクリプトを実行できるようにするために使用しています。 JavaScriptエディターを使用しているため、これはすぐに役立ちます。
  • frameBorder
    これは、iframeの境界線の太さを定義するだけです。
  • widthheight
    これは、iframeの幅と高さを定義します。

これらの用語は、あなたにとってより意味のあるものになるはずです。 次に進んで、 srcDocのHTMLテンプレートドキュメントを保持する状態を宣言しましょう。 上記のコードブロックをよく見ると、 srcDoc属性に値を渡したことがわかります: srcDoc ={srcDoc}useState() Reactフックを使用してsrcDoc状態を宣言しましょう。 これを行うには、 App.jsファイルで、他の状態を定義した場所に移動し、次の状態を追加します。

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

状態を作成したので、次に行うことは、コードエディタに入力するたびに結果を状態で表示することです。 しかし、私たちが望んでいないのは、キーを押すたびにコンポーネントを再レンダリングすることです。 それを念頭に置いて、先に進みましょう。

結果を表示するためのIframeの設定

HTML、CSS、JavaScriptのいずれかのエディターにそれぞれ変更があるたびに、 useEffect()がトリガーされ、更新された結果がiframeにレンダリングされます。 App.jsファイルでこれを行うためにuseEffect()を書いてみましょう:

まず、 useEffect()フックをインポートします。

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

useEffect()を次のように記述しましょう。

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

ここでは、HTML、CSS、およびJavaScriptエディターに対して宣言した値が変更または更新されたときに常に実行されるuseEffect()フックを作成しました。

なぜsetTimeout()を使用する必要があったのですか? それなしでこれを書いた場合、エディターでキーを1回押すたびに、iframeが更新されますが、これは一般的なパフォーマンスには適していません。 そのため、 setTimeout()を使用して更新を250ミリ秒遅らせ、ユーザーがまだ入力しているかどうかを知るのに十分な時間を与えます。 つまり、ユーザーがキーを押すたびにカウントが再開されるため、iframeは、ユーザーが250ミリ秒アイドル状態(入力していない)の場合にのみ更新されます。 これは、キーが押されるたびにiframeを更新する必要がないようにするための優れた方法です。

上記で次に行ったことは、 srcDocを新しい変更で更新することでした。 上で説明したように、 srcDocコンポーネントは、指定されたHTMLコンテンツをiframeにレンダリングします。 このコードでは、ユーザーがHTMLエディターに入力したコードを含むhtml状態を取得し、テンプレートのbodyタグの間に配置して、HTMLテンプレートを渡しました。 また、ユーザーがCSSエディターで入力したスタイルを含むcss状態を取得し、それをstyleタグ間で渡しました。 最後に、ユーザーがJavaScriptエディターに入力したJavaScriptコードを含むjs状態を取得し、 scriptタグ間で渡しました。

setSrcDocの設定では、通常の引用符( ' ' )の代わりにバッククォート( ` ` )を使用していることに注意してください。 これは、上記のコードで行ったように、バックティックによって対応する状態値を渡すことができるためです。

useEffect()フックのreturnステートメントは、メモリリークを回避するために、完了時にsetTimeout()をクリアするクリーンアップ関数です。 ドキュメントには、 useEffectに関する詳細があります。

現在のプロジェクトは次のようになります。

私たちのプロジェクトは現在どのように見えますか
(大プレビュー)

CodeMirrorアドオン

CodeMirrorアドオンを使用すると、他のコードエディターにあるような機能でエディターを拡張できます。 開始タグが入力されたときに自動的に閉じタグが追加される例と、開始ブラケットが入力されたときに自動的に閉じられるブラケットの別の例を見ていきましょう。

最初に行うことは、このアドオンをApp.jsファイルにインポートすることです。

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

ControlledEditorComponentオプションでそれを渡しましょう:

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

これが私たちが持っているものです:

私たちのプロジェクトの見た目
(大プレビュー)

これらのアドオンを大量にエディターに追加して、より豊富な機能を提供することができます。 ここでは、それらすべてを確認することはできませんでした。

これで完了です。アプリのアクセシビリティとパフォーマンスを向上させるためにできることについて簡単に説明しましょう。

ソリューションのパフォーマンスとアクセシビリティ

私たちのWebコードエディタを見ると、いくつかの点が間違いなく改善される可能性があります。

私たちは主に機能性に注意を払っていたので、デザインを少し無視したかもしれません。 アクセシビリティを向上させるために、このソリューションを改善するためにできることがいくつかあります。

  1. 現在開いているエディターのボタンにactiveクラスを設定できます。 ボタンを強調表示すると、ユーザーが現在作業しているエディターを明確に示すことができるため、アクセシビリティが向上します。
  2. エディターがここにあるものよりも多くの画面スペースを占めるようにしたい場合があります。 もう1つ試すことができるのは、横のどこかにドッキングされているボタンをクリックするだけでiframeをポップアップさせることです。 そうすることで、エディターにより多くの画面スペースが与えられます。
  3. この種のエディターは、モバイルデバイスで簡単なエクササイズを実行したい人に役立つため、モバイルに完全に適合させる必要があります(上記のモバイルに関する両方のポイントは言うまでもありません)。
  4. 現在、ロードした複数のテーマの中からエディターコンポーネントのテーマを切り替えることができますが、ページの一般的なテーマは同じです。 ユーザーがレイアウト全体でダークテーマとライトテーマを切り替えることができるようにすることができます。 これはアクセシビリティに優れており、明るい画面を長時間見ていることによる人々の目の負担を軽減します。
  5. 主に、外部ドキュメントではなく内部HTMLドキュメントをiframeに読み込んでいたため、iframeのセキュリティ問題については検討しませんでした。 したがって、iframeはユースケースに適しているため、これを慎重に検討する必要はありません。
  6. iframeの場合、別の考慮事項はページの読み込み時間です。これは、iframeに読み込まれるコンテンツは、通常、制御できないためです。 私たちのアプリでは、iframeコンテンツが外部にないため、これは問題ではありません。

パフォーマンスとアクセシビリティは、アプリケーションを構築するときに、ユーザーにとってアプリケーションがどれだけ有用で使いやすいかを決定するため、多くの検討に値します。

Shedrackは、Reactアプリのパフォーマンスを改善および最適化する方法をうまく説明してきました。 チェックする価値があります!

結論

さまざまなプロジェクトに取り組むことで、さまざまなテーマについて学ぶことができます。 この記事を読み終えたので、コードエディターをより充実させ、UIを刷新し、上記で概説したアクセシビリティとパフォーマンスの問題を修正するために、より多くのアドオンを試して、経験を自由に拡張してください。

  • このプロジェクトのコードベース全体は、GitHubで入手できます。

Codesandboxのデモは次のとおりです。

リンクと資料

  • 「GoogleChromeのポータル:Iframeと同じですが、より良く、より悪く」、Daniel Brain
  • 「パフォーマンスの最適化」、Reactドキュメント
  • 「ユーザーマニュアルおよびリファレンスガイド」、CodeMirrorドキュメント