IoTおよびメーカー向けのSVGWebページコンポーネント(パート1)
公開: 2022-03-10IoT市場はまだ初期段階ですが、勢いを増しています。 私たちはIoTの歴史の最前線にいます。 市場は2015年から2020年までの5年間で4倍になります。Web開発者にとって、このIoTの成長は重要です。 IoTWeb技術にはすでに大きな需要があります。
多くのデバイスは地理空間的に分散され、その所有者はリモート制御と管理を望んでいます。 テレオペレーション用のチャネルを作成するには、完全なWebスタックを作成する必要があります。 また、相互作用は一度に1つ以上のIoTデバイスと行われます。 相互作用は、物理的な世界のリアルタイムでなければなりません。
このディスカッションでは、 Vue.jsを触媒として使用するインターフェース要件を掘り下げ、多くの代替手段からのWebページからデバイスへの通信の1つの方法を示します。
このディスカッションで計画されている目標のいくつかを次に示します。
- IoTヒューマンマシンインターフェイスのグループ(これらを「パネルグループ」と呼ぶ場合があります)をホストする単一ページのWebアプリSPWAを作成します。
- サーバーに照会した結果として、パネルグループIDのリストを表示します。
- クエリの結果として、選択したグループのパネルを表示します。
- パネルディスプレイが遅延ロードされ、すばやくアニメーション化されることを確認します。
- パネルがIoTデバイスと同期していることを確認します。
IoTとWebページの急速な成長
Webページとリアルタイムの物理プロセスとの同期に加えて、ハードウェアの視覚化とリモート制御のためのグラフィックスの表示は、このIoTの将来に固有のWebページの問題解決の領域内にあります。
私たちの多くはIoTプレゼンテーション手法の検索を開始していますが、現在使用を開始できるいくつかのプレゼンテーション手法に加えて、いくつかのWeb標準があります。 これらの標準と手法を一緒に検討することで、このIoTの波に参加できます。
ダッシュボードとデータの視覚化が求められています。 さらに、フォームやディスプレイリスト、テキストコンテンツを提供するWebページを超える需要が高まっています。 IoTのダッシュボードは、絵でアニメーション化する必要があります。 アニメーションは、ユーザーにマシンの状態の検証ビューを提供するために、リアルタイムの物理プロセスと同期する必要があります。 火炎燃焼の有無などの機械の状態は、アプリケーションの状態よりも優先され、オペレーターに重要な情報、場合によっては安全情報さえも提供します。
ダッシュボードには、データの視覚化以上のものが必要です。 IoTの一部は、センサーだけでなく、インターフェースを制御するデバイスであることを覚えておく必要があります。 ハードウェア実装では、MCUはスイッチ、しきい値スイッチ、パラメーター設定などで拡張されます。 それでも、これらのハードウェア制御コンポーネントの代わりにWebページが使用される場合があります。
新しいことは何もありません。 ハードウェア用のコンピューターインターフェイスは長い間存在していましたが、これらのインターフェイスでのWebページの使用が急速に増加していることは、現在の経験の一部です。 WebRTCとSpeechAPIは、2012年に開始された開発パスにあります。WebSocketsも同様の時間枠で開発されています。
IoTは長い間私たちの頭の中にありました。 IoTは1832年以来、人間の対話の一部となっています。しかし、1926年頃にテスラによって構想されたことがわかってきたIoTとワイヤレス。Forbes2018Stateof Iotは、IoTの現在の市場の焦点を示しています。 Web開発者にとって興味深いのは、この記事でダッシュボードを呼び出すことです。
「IoTの早期採用者または支持者は、ダッシュボード、レポート、分析、高度な視覚化、およびデータマイニングに不可欠なデータストリームを提供するIoTユースケースを優先します。」
IoT市場は巨大です。 この市場規模の記事は、表示されるデバイスの数の予測を提供します:2018:231.4億⇒2025:754.4億。 そして、それに財務数値を入れようとします:2014年:2.99兆ドル⇒2020年:8.90兆ドル。 IoTスキルの需要は最も急速に成長します:IoTinDemand。
デバイスを制御および監視するための明確なインターフェイスを開発するにつれて、インターフェイスを開発するための新しい問題が発生します。 何十億ものデバイスはすべて、多くの人々(または組織)によって所有されます。 また、各人は任意の数のデバイスを所有できます。 おそらく、一部のデバイスでさえ共有されるでしょう。
マシン制御用に作成された最新のインターフェースは、特定のマシンまたは数台のマシンのインストールに固有の明確に定義されたレイアウトを持っていることがよくあります。 たとえば、スマートハウスでは、ハイエンドシステムには、慎重に配置されたデバイス用のパネルを備えたLCDがあります。 しかし、IoTのWebバージョンで成長するにつれて、デバイスの動的な、さらにはモバイルストリーム用のパネルがいくつも存在するようになります。
デバイスのパネルの管理は、ソーシャルWebサイトでのソーシャル接続の管理と同様になります。
「私たちのユーザーインターフェイスは、特定のユーザーごとに一度に表示する必要のある高度にアニメーション化されたリアルタイムパネルを管理する上で動的である必要があります。」
ダッシュボードは、単一ページのWebアプリSPWAです。 そして、パネルのデータベースを想像することができます。 したがって、1人のユーザーが地球上に散らばっているデバイスの多数のパネルと構成にアクセスする場合、SPWAはオンデマンドでパネルコンポーネントにアクセスする必要があります。 パネルとそれをサポートするJavaScriptの一部は、遅延してロードする必要があります。
「私たちのインターフェースは、フレームワークを再初期化せずに非同期コンポーネントバインディングを組み込むことができるWebページフレームワークと連携する必要があります。」
Vue.js、WebSockets、MQTT、SVGを使用して、IoT市場に参入しましょう。
推奨読書: Vue.jsを使用したインタラクティブなインフォグラフィックの構築
IoTWebアプリの高レベルアーキテクチャ
IoT Webページのインターフェースを設計する場合、常に多くのオプションがあります。 1つのオプションは、1つのページを1つのデバイス専用にすることです。 ページはサーバー側でレンダリングされる場合もあります。 サーバーは、デバイスにクエリを実行してセンサー値を取得し、その値をHTML文字列の適切な場所に配置する役割を果たします。
私たちの多くは、変数値を配置する場所を示す特別なマーカーを使用してHTMLテンプレートを作成できるツールに精通しています。 このようなテンプレートで{{temperature}}
を見ると、デバイスから照会された温度を取得し、 {{temperature}}
記号をそれに置き換えるようにビューエンジンに指示されます。 したがって、サーバーがデバイスにクエリを実行し、デバイスが応答し、ページをレンダリングし、ページを配信するのを待った後、ユーザーは最終的にデバイスによって報告された温度を確認できるようになります。
デバイスアーキテクチャごとのこのページでは、ユーザーはデバイスにコマンドを送信したい場合があります。 問題ありません。彼はHTMLフォームに記入して送信できます。 サーバーには、デバイス専用のルートがある場合もあれば、デバイスのタイプとデバイスID用のルートがある場合もあります。 次に、サーバーはフォームデータをメッセージに変換してデバイスに送信し、デバイスハンドラーに書き込んで、確認応答を待ちます。 その後、サーバーは最終的にPOSTリクエストに応答し、デバイスに問題がないことをユーザーに通知します。
多くのCMSは、ブログエントリなどを更新するためにこのように機能します。 何も奇妙に思えません。 HTML over HTTPには、レンダリングされたページを取得し、Webサーバーで処理されるフォームデータを送信するための設計が常に備わっているようです。 さらに、何千ものCMSから選択できます。 したがって、IoTシステムを立ち上げるために、何千ものCMSを調べて、どれがその仕事に適しているかを確認するのは合理的だと思われます。 または、最初にCMSに1つのフィルターを適用することもできます。
私たちは、私たちが扱っているもののリアルタイムの性質を考慮に入れなければなりません。 したがって、元の形式のHTMLは多くのエンタープライズタスクに非常に適していますが、IoT管理の配信メカニズムになるには少しの助けが必要です。 したがって、HTMLがこのIoTジョブを実行するのに役立つCMSまたはカスタムWebサーバーが必要です。 また、CMSがサーバー機能を提供すると想定しているため、サーバーについて考えることもできます。 サーバーはイベント駆動型アニメーションを提供する必要があるため、ページを100%ファイナライズされた静的印刷にすることはできません。
デバイスにリンクされたWebページの選択をガイドする可能性のあるいくつかのパラメーターを次に示します。
- センサーデータとその他のデバイスステータスメッセージを非同期で受信します。
- クライアントのページのセンサーデータをレンダリングします(ほぼ当然のことながら1)。
- コマンドを特定のデバイスまたはデバイスのグループに非同期で公開します。
- オプションで、サーバーを介してコマンドを送信するか、サーバーをバイパスします。
- デバイスとユーザー間の所有権関係を安全に維持します。
- 干渉したりオーバーライドしたりしないことで、重要なデバイスの動作を管理します。
このリストは、選択したデバイスへのインターフェイスとして機能する1ページだけを考えるときに思い浮かびます。 コマンドやデータに関しては、デバイスと自由に通信できるようにしたいと考えています。
このページについては、Webサーバーに1回だけ依頼する必要があります。 Webサーバー(または関連するアプリケーション)が安全な通信経路を提供することが期待されます。 また、経路はサーバーを経由する必要はありません。または、サーバーがセンサーからのデータの1ページの通信を処理する以外に優先度の高いタスクを実行する可能性があるため、サーバーを完全に回避する必要があります。
実際、センサーから1秒に1回データが着信することは想像できますが、Webサーバー自体が、数千の個々のセンサーストリームに数千の視聴者を掛けたものに対して2回目の更新で一定の秒数を提供することは期待できません。 もちろん、Webサーバーは負荷分散フレームワークでパーティション化またはセットアップできますが、センサーの配信とハードウェアへのコマンドのマーシャリング用にカスタマイズされた他のサービスもあります。
ページがデバイスとの安全な通信チャネルを確立できるように、Webサーバーはパケットを配信する必要があります。 通過するメッセージの種類をある程度管理できないチャネルでメッセージを送信する場合は注意が必要です。 デバイスが中断可能なモードにあるかどうか、またはデバイスが制御不能になった場合にユーザーのアクションが必要になる可能性があるかどうかについて、ある程度の知識が必要です。 したがって、Webサーバーは、クライアントがデバイスについて詳しく知ることができる適切なリソースを取得するのに役立ちます。 メッセージングは、MQTTサーバーのようなもので行うことができます。 また、ユーザーがWebサーバーを介してパネルにアクセスしたときに開始できるMQTTサーバーを準備するためのサービスがいくつかある可能性があります。
リアルタイム要件のある物理的な世界と追加のセキュリティ上の考慮事項のために、私たちの図は元の図とは少し異なります。
ここで止まることはありません。 デバイスごとに1つのページを設定することは、応答性が高く、通信を適切に処理できる場合でも、私たちが求めていたものではありません。 ユーザーが自分のアカウントにログインしてダッシュボードにアクセスすることを想定する必要があります。 そこから、彼はコンテンツプロジェクト(おそらく彼が取り組んでいるプロジェクト)のリストを要求します。 リストの各項目は、いくつかのリソースを参照します。 クリックまたはタップしてアイテムを選択すると、パネルのコレクションにアクセスできます。各パネルには、特定のリソースまたはIoTデバイスに関する情報が含まれています。
ユーザーのインターフェースアクションの結果として生成されたクエリに応答して配信されるパネルの数は、ライブデバイスと対話するパネルである可能性があります。 したがって、パネルが表示されるとすぐに、リアルタイムのアクティビティが表示され、デバイスにコマンドを送信できるようになることが期待されます。
パネルがページ上でどのように表示されるかは、設計上の決定事項です。 フローティングウィンドウの場合もあれば、スクロール可能な背景のボックスの場合もあります。 それがどのように提示されても、パネルは時間、温度、圧力、風速、またはあなたが想像できる他のものを刻みます。 パネルは、さまざまなグラフィックスケールに関してアニメーション化されることを期待しています。 温度は温度計として、速度は半円形の速度計として、音はストリーミング波形として表示できます。
Webサーバーには、パネルのデータベースへのクエリが与えられ、デバイスが物理的に利用可能である必要がある場合に、適切なパネルを適切なユーザーに配信する役割があります。 さらに、さまざまな種類のデバイスが存在することを考えると、各デバイスのパネルは異なる可能性があります。 したがって、Webサーバーは、パネルのレンダリングに必要な画像情報を配信できる必要があります。 ただし、ダッシュボードのHTMLページには、可能なすべてのパネルをロードする必要はありません。 いくつになるかわかりません。
ダッシュボードページの選択をガイドする可能性のあるいくつかのパラメータ、それが行うべきことは次のとおりです。
- 関連するデバイスパネルのグループを選択する方法を提示します。
- いくつかのデバイスに対して同時デバイス通信メカニズムを利用します。
- ユーザーが要求したときにデバイスパネルをアクティブにします。
- 遅延ロードされたグラフィックを組み込んで、独自のパネルデザインを実現します。
- 各パネルに関してセキュリティトークンとパラメータを利用します。
- ユーザーの検査下にあるすべてのデバイスとの同期を維持します。
ゲームがどのように変化するかを見ることができますが、ダッシュボードデザインの世界では、ゲームはしばらくの間、あちこちで少し変化しています。 自分自身を稼働させるには、最新の便利なページ開発ツールに絞り込む必要があります。
パネルをレンダリングする方法から始めましょう。 これはすでに大きな仕事のようです。 さまざまな種類のパネルを想像しています。 しかし、音楽DAWを使用したことがあれば、彼らがグラフィックを使用して、パネルを昔のバンドで使用されていたアナログデバイスのように見せていることがわかります。 DAWのすべてのパネルは、サウンドを操作するプラグインによって描画されます。 実際、これらのDAWのプラグインの多くは、SVGを使用してインターフェースをレンダリングする可能性があります。 そのため、SVGインターフェースの処理に限定します。これは、想像できる任意のグラフィックにすることができます。
パネル用のSVGの選択
もちろん、私はDAWが好きで、それを例として使用しますが、SVGはWebページの標準です。 SVGはW3C標準です。 これは、線画をWebページに運ぶためのものです。 SVGは、iFrameに住むために必要な、Webページの二級市民でした。 しかし、HTML5以来、それは一級市民でした。 おそらく、SVG2が出たとき、それはフォーム要素を使用できるようになるでしょう。 今のところ、フォーム要素はSVGの外部オブジェクトです。 しかし、それは私たちがSVGをパネルの基板にすることを妨げるものではありません。
SVGは描画、表示用に保存でき、遅延ロードできます。 実際、コンポーネントシステムを調べると、SVGをコンポーネントテンプレートに使用できることがわかります。 このディスカッションでは、Vue.jsを使用してパネルのコンポーネントを作成します。
入手しやすい線画プログラムがたくさんあるので、SVGの描画は難しくありません。 お金を使うと、SVGをエクスポートするAdobeIllustratorを入手できます。 Inkscapeは、しばらくの間SVG作成のgotoでした。 これはオープンソースであり、Linuxでうまく機能しますが、MacとWindowsでも実行できます。 次に、オープンソースであるいくつかのWebページSVG編集プログラムといくつかのSaaSバージョンがあります。
私はオープンソースのWebベースのSVGエディターを探していました。 周りを見回した後、私はSVG-Editに出くわしました。 おそらくSVGベースのブログなどを作成している場合は、それを自分のWebページに含めることができます。
作業内容をファイルに保存すると、SVG-Editによってブラウザにダウンロードされ、ダウンロードディレクトリからファイルを取得できます。
私が描いた写真は、積分器を制御するANDゲートを示しています。 これは、MCUのパネルに通常表示されるものではありません。 パネルには、おそらくANDゲート入力の1つを供給するためのボタンがあるかもしれません。 次に、積分器の出力を読み取るADCからの表示がある場合があります。 おそらくそれは時間軸上の折れ線グラフになるでしょう。 ほとんどのパネルには、ユーザーがMCU内で何が起こっているかを関連付けることができるグラフィックがあります。 そして、私たちの回路がどこにでも住むつもりなら、それはMCUの中にあります。
それでも、私たちの電子図を使用してアニメーションについて議論することができます。 私たちがやりたいのは、SVGを見て、何らかの方法で変更したいDOMタグのいくつかをどこで取得できるかを確認することです。 次に、小さなバニラJavaScriptとタイマーを使用してSVGをアニメーション化できます。 ANDゲートを異なる色で点滅させましょう。
私たちが探しているSVGは、次のコードボックスにあります。 ユーザーは非常に満足しますが、プログラマーにとってはあまり親しみやすいようには見えません。 それでも、操作したいDOM要素を見つけるための手がかりはまだいくつかあります。 まず、ほとんどのSVG描画ツールには、オブジェクトのプロパティ、特にid
属性を取得する方法があります。 SVG-Editにも方法があります。 エディターで、ANDゲートを選択し、ツールバーを確認します。 id
とCSS class
のフィールドも表示されます。
何らかの理由で編集ツールにアクセスできない場合は、ブラウザーでSVGを開いて、DOMを調べることができます。 いずれにせよ、ゲートのid
=“ svg_1”であることがわかりました。
<svg width="640" height="480" xmlns="https://www.w3.org/2000/svg" xmlns:svg="https://www.w3.org/2000/svg"> <g class="layer"> <title>Layer 1</title> <path d="m80.59881,87.020171l14.714795,0m-14.714793,-11.938687l14.714797,0.000004m-0.033867,-6.543869l0,24.758504c42.377882,2.221929 43.364812,-27.139117 0,-24.758504zm47.366321,12.333056l-15.303943,0m-48.188699,-6.489897l1.454753,0l0,1.454751l-1.454753,0l0,-1.454751zm-0.068425,11.869359l1.454753,0l0,1.454753l-1.454753,0l0,-1.454753zm63.545246,-6.089294l1.454751,0l0,1.454751l-1.454751,0l0,-1.454751z" fill="#FF0000" stroke="#000000"/> <path d="m48.58886,119.662231l18.234678,0l2.523043,-7.173309l4.128604,13.808613l4.587337,-13.987948l4.013933,13.808613l4.35797,-13.629278l4.35797,13.718944l2.408353,-6.72497l18.349357,0m-64.482612,-0.623112l1.515724,0l0,1.515728l-1.515724,0l0,-1.515728zm64.484275,-0.103111l1.515721,0l0,1.515728l-1.515721,0l0,-1.515728z" fill="#FF0000" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="rotate(90.3367 80.0675 119.304)"/> <polygon cx="108.5" cy="79.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="#000000"/> <polygon cx="215.5" cy="192.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="165.5" cy="164.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="161.5" cy="138.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="160.5" cy="161.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <g> <path d="m225.016923,53.008793l0,3.419331m-4.558966,-1.709666l9.11791,0m10.303228,4.235512l-25.770656,0m-34.429182,0l24.544724,0m0.220544,-4.058194l1.543807,0l0,8.164451l-1.543807,0l0,-8.164451zm7.939567,-4.473673l1.543805,0l0,16.999955l-1.543805,0l0,-16.999955zm-34.176663,8.126854l1.474036,0l0,0.747515l-1.474036,0l0,-0.747515zm61.677552,0.018809l1.474038,0l0,0.747515l-1.474038,0l0,-0.747515z" fill="#FF0000" sides="3" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/> <polygon cx="171.5" cy="159.5" edge="43.256342" fill="#ffffff" orient="x" points="223.47406005859375,91.5 186.01296997070312,113.128173828125 186.01296997070312,69.871826171875 223.47406005859375,91.5 " shape="regularPoly" sides="3" stroke="#000000" stroke-width="null" strokeWidth="null" strokecolor="#000000"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171" x2="186" y1="103.5" y2="103.5"/> <path d="m130.801817,80.659041l15.333707,0l2.12165,-4.564833l3.47178,8.787299l3.857534,-8.901421l3.375353,8.787299l3.664657,-8.673176l3.664657,8.730237l2.025206,-4.279526l15.430142,0m-54.224016,-0.396526l1.274586,0l0,0.964554l-1.274586,0l0,-0.964554zm54.225414,-0.065616l1.274584,0l0,0.964554l-1.274584,0l0,-0.964554z" fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171.5" x2="171.5" y1="103.75" y2="135.388167"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="177.75" x2="177.75" y1="58.75" y2="80.255951"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="223.75" x2="266.854524" y1="91.75" y2="91.75"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="241.75" x2="241.75" y1="59.75" y2="91.754167"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="168.25" x2="180.75" y1="135.75" y2="135.75"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="169.75" x2="179.25" y1="138.5" y2="138.5"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" x1="171" x2="179.75" y1="141.25" y2="141.25"/> </g> </g> </svg>
今必要なのは小さなJavaScriptだけです。 最初に、要素属性「fill」が存在することに注意してください。 次に、次のような単純なプログラムがあります。
<html> <head> </head> <body> <!-- ALL THE SVG FROM ABOVE GOES HERE --> </body> <html> </svg> <script> // Set up a timer interval flash the color. var gateElement = document.getElementById("svg_1"); if ( gateElement ) { setInterval( () => { var fillC = gateElement.getAttribute("fill"); gateElement.setAttribute("fill", (fillC == "#00FF00") ? "#FF0000" : "#00FF00" ); }, 2000 ) } </script>
最小限のHTMLページであることに注意してください。 コードを切り取って、お気に入りのエディターに貼り付けることができます。 そして、コメントを置き換えるためにSVGをカットアンドペーストすることを忘れないでください。 私のバージョンのChromeでは、JavaScriptセクションを作成するためにページがHTMLである必要があります。 つまり、それはまだSVGを別のものとして扱っている1つのブラウザーです。 しかし、それは<iframe>
の時代から遠く離れています。
正しくカットアンドペーストすると、ページが表示され、ANDゲートが赤から緑に何度も変わるのを見ることができます。
推奨読書:パスへのSVGサークル分解
VUEコンポーネントからのパネルの構築
私たちはすでに単一のパネルを生き生きとさせるための道を進んでいますが、パネルの大規模なコレクションを賢明な方法で管理したい場合は、私たちの仕事を切り取ってもらうでしょう。 これは、最初の例に基づいて単純に構築した場合に特に当てはまります。
最初の例は、オブジェクトビューを非同期的に変更する方法を示していますが、マシンを管理するデータオブジェクトはもちろん、データオブジェクトの状態にビューを関連付ける方法も示していません。 setInterval
デモンストレーションをfetch
ハンドラーに置き換える方法は確かに理解できますが、SVGを含むページを提供するWebサーバーからマシンの状態を取得することさえできない場合があります。 また、データを取得するときに、プログラムは指定されたページのDOM構造について知る必要があります。
幸い、Vueなどのフレームワークが普及しており、多くの作業を節約できます。
Vueについて知るのは簡単です。 Vueのドキュメントは非常にアクセスしやすいです。 したがって、この議論があまりにも先に進んでいる場合は、独自のWebサイトでVueについて学ぶことに時間を費やすことができます。 しかし、Smashingページ内には非常に良い議論があります。 Krutie Patelは、インフォグラフィックの作成に関するすばらしい記事を書きました。 Souvik Sarkarが、Vueを使用して天気ダッシュボードを作成する方法を説明します。
関連パネルのグループ選択
最初のステップとして、パネルのグループの検索に取り組む必要があります。 これを最初に行う理由の1つは、それが人間の相互作用のフレームワークレベルにあることです。
ユーザーは自分が興味を持っているものを検索します。おそらく、彼は1つの町の場所にあるすべてのデバイスに興味を持っています。 おそらく、彼は液体製品のバッチを多数持っており、各バッチがIoTデバイスの小さなコレクションによって管理される1つのタイプの製品に絞り込みたいと考えています。 したがって、ユーザーは最初に検索して小さなリストを取得します。
プロセスは次のとおりです。
- 機能/パラメータでパネルのグループを検索します。
- グループを表すアイコンのリストを表示します。
- アイコンを選択します(クリック/タップ)。
- アイコンで識別されるパネルが表示されたら、使用を開始します。
これが良い最初のステップであるもう1つの理由は、Vueを最も単純な形式で使用できることです。 ビルドツールは必要ありません。 HTMLにスクリプトタグを付けてvue.js
を含めるだけです。 実際、ダウンロードする必要はありません。 vue.js
の作業コピーが提供されているサイトがあります。
必要なのは次のタグだけです。
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
インストールに関するVueのドキュメントからスクリプトタグを直接コピーしました。
次に、アイコンを読み込んでクリックするものにできるWebページが必要です。 Vueはそれを非常に簡単にします。 実際、私はVueを使用してTwitterリストを管理するための小さなアプリを作成しました。 テキストフィールドを管理するだけです。 アイコンを使用するSPWAよりも少し単純なので、それを確認してから、目的のシングルページアプリフレームワークに変更できます。
ページの外観の一部は次のとおりです。
これはかなり単純なページのように見えます。 外側の各数値エントリは、1つまたは2つのツイートを含むタイムスロットです。 2番目のツイートはオプションです。 ツイートを編集すると、VueメカニズムがJavaScriptオブジェクトを更新します。 このページでは、ユーザーが「エントリの更新」ボタンをクリックして、ボタンハンドラー機能を介して何かが変更されたことをサーバーに通知することができます。
ボタンハンドラーがデータをサーバーに中継するには、VueデータオブジェクトをJSON文字列に変更する必要があります。 ここで、VueオブジェクトをJSONに変換するのがどれほど難しいか疑問に思うかもしれません。 1行のコードであることがわかります。 この行は次のソースコードで見つけることができますが、もっと速く見つけたい場合は、ソースコードの後の段落で強調表示されています。
ページはシンプルに見えます。 見た目はだましている可能性があります。 もちろん、ページはシンプルに見えますが、コードはシンプルですか? はい、確かにそうです! Vueを使用して、ページはフィールドのコンテンツをほぼ魔法のように管理します。 コードは次のとおりです。
<!DOCTYPE html> <html lang="en" prefix="og: https://ogp.me/ns#"> <!-- define microdata scope and type --> <head itemscope itemtype="https://schema.org/Article"> <title>Tweet Keeper</title> <style> body { margin: 2em; } .entryart { border: solid 1px navy; width: 80%; padding: 2px; padding-left: 6px; margin-bottom: 3px; background-color: #EEF4EE; } </style> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> </head> <body onload="GetTweets()"> <!-- some old fashioned handling --> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div itemscope itemtype="https://schema.org/Article"> <h1 itemprop="name">mangage tweets</h1> <p itemprop="description">My personal Tweet engine. This page accesses a personal tweet page that belongs to {{tweetOwner}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button>Update Entries</button> </div> <!-- Here is a Vue loop for generating a lit --> <ol> <li v-for="tweet in tweets"> <!-- here is the first tweet represented as an object with a lable and tweet text --> <div class="entryart"> <input v-model="tweet.def[0].label" /> <input v-model="tweet.def[0].tweet" /> </div> <!-- here is the second tweet in the slot. But, notice that it is optional. --> <div class="entryart" v-if="tweet.def.length > 1"> <input v-model="tweet.def[1].label"/> <input v-model="tweet.def[1].tweet"/> </div> </li> </ol> </div> <script> var twtApp = new Vue({ el: '#tweetAppDiv', data: { tweets: [ // Where is the data? Still on the server.s ], tweetOwner : "Lucky Dude" // picked a name for demo } }); </script> </body> </html> <script> // Notice that you don't have to do everything in the Vue framework. // Here we are using some native API calls var gDefaultPostInfo = { // there server is beyond simple - an example from node.js docs method: 'POST', // or 'PUT' mode: "cors", // no-cors, cors, *same-origin cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached credentials: "same-origin", // include, *same-origin, omit redirect: "follow", // manual, *follow, error referrer: "no-referrer", // no-referrer, *client body: "", headers:{ 'Content-Type': 'application/json' } } // // // recall the "onload" function GetTweets(event) { var url = "https://localhost:8080/twitlist1.json" // We have a fixed file name. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. twtApp.tweets = newData // the page update right away with new data. }); }); } function sendTweets() { // recall the button up above. This is not a Vue style button, but still in the Vue app. var url = "https://localhost:8080/" var data = twtApp.tweets; // GET THE DATA OUT OF VUE. That's all folks. // // so happens that Vue pulls out the right data and stringifies it. var jdata = JSON.stringify(data); // data can be `string` or {object}! // gDefaultPostInfo.body = jdata; // that's for fetch - not Vue related // fetch(url,gDefaultPostInfo).then(res => { // We use fetch to POST as well as GET res.json() }).then(response => { console.log('Success:', JSON.stringify(response)) // promises }).catch(error => { console.error('Error:', error) }); } // // // </script>
それで、フレームワークの力を語る驚くべき線を強調するために、ここで繰り返しましょう:
A.これはデータを引き出しています。
postOptionsObject.body = JSON.stringify(twtApp.tweets);
B.これは、データをVueに入れ、画面の更新を確認しています。
twtApp.tweets = JSON.parse(text) // text is the server response
それはどのくらいの仕事ですか?
データがIoTのパネルを更新する方法を表現するための優れた方法があるようです。
それでは、ツイートをWebサーバーからコンポーネントをフェッチするように設計されたクリック可能なアイコンに変えましょう。
ツイートからパネルフェッチアイコンまで
人々はアイコンにSVGを使うのが好きです。 私が知る限り、彼らは他のものよりもSVGの使用を好みます。 私は、SVGで作成されたアイコンを販売または配布しているWebサイトの数だけを調べています。 セールスポイントは、ライングラフィックスのバイト数が画像よりも少ないことです。 また、ボタンのような動作をする画像のリストを要求する場合、SVGがiframeで使用されていた時代にPNGまたはJPEGを取得した可能性があります。 ただし、Vueの寄稿者リストには、アイコンの提供に役立つライブラリを見つけることもできます。
We can turn the tweets page into an icon list returned as a search result. Just a little code has to be changed. Of course, there are a few things to be careful about if we want SVG icons to be loaded as buttons. Vue provides mechanisms for putting HTML into the application. These mechanisms have to be used or DOM elements fetched from the server don't get interpreted.
Here is the kind of rendering you can get from view if you follow your first impulse in creating a handlebars style variable location in the application DOM.
Here is the code that produces the result in the picture:
<div> <div class="entryart"> <span class="oneItem" v-for="icon in iconList"> {{icon}} </span> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } }); </script>
Notice that we have gone from looping over tweets to looping over icons. tweet in tweets
changed into icon in iconList
. Our twtApp
hooks into the DOM element #tweetAppDiv
, while our iconApp
hooks into the DOM element #iconAppTry
. Within the Vue option object, the data
subobject has a tweets
in the first app, and iconList
in the second. The fields are both empty arrays that receive data when the fetch
routine does its job.
But, we have imitated our tweet app too closely. In the code above, the iconList is an array, and the server is expected to send an array of strings. So, let's say the server has sent us HTML, and we have it properly decoded with the array assigned to data.iconList
. Then, the picture above can be seen.
Now, let's change the code just a little. In this revised code, we can see the following:
v-html="icon">
Vue responds to the v-html syntax by putting in the DOM of the icon
element. Notice that the syntax is included after the loop directive as another attribute to the span
tag.
By removing the handlebars
syntax and using v-html
, our picture changes to something more comprehensible:
<div> <div class="entryart"> <span class="oneItem" v-for="icon in iconList" v-html="icon"> </span> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry2', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } }); </script>
While v-html
is a quick way to do things, the Vue team recommends using components to get the desired HTML into the page. That seems like a good idea, and we shall soon set about doing that.
But, let's use the v-html
syntax for our next example.
It's time to set up our working example for fetching SVG icons. Let's have those icons be responsive to a button click. Once those are working, we can get the panels associated with an icon.
Let's suppose that the SVG required for icons is stored in a database. For our example, we can just fetch a JSON file from the server. The grown-up version of the icon server would store many such files in a database, and deliver them to the page with the same mechanisms.
Also, it's best if the SVG arrives on the page URL encoded since we will be using JSON parse. The SVG can be decoded by calling JavaScript's decodeURIComponent
function.
In order to simulate the response to searching, we can make use of several JSON files. The page can have one button for each file. Here is the code for the page:
<!DOCTYPE html> <html lang="en" prefix="og: https://ogp.me/ns#"> <!-- define microdata scope and type --> <head itemscope itemtype="https://schema.org/Article"> <title>Search Bar</title> <style> body { margin: 2em; } div { margin: 6px; } .entryart { border: solid 1px navy; width: 80%; padding: 2px; padding-left: 6px; margin: 2px; margin-bottom: 3px; background-color: #EEF4EE; } .oneItem { background-color: #EEFFFF; margin: 2px; padding: 4px; border: solid 1px purple; } </style> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> </head> <body> <!-- some old fashioned handling --> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Request MCU Groups</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button>Find All</button> <button>Find 5 Point</button> <button>Find 6 Point</button> </div> <!-- Here is a Vue loop for generating a lit --> <div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } } }); </script> </body> </html> <script> // // recall the "onclick" on the <buttons> function GetIcons(points) { // special file names instead of search parameters // var url = (points == 11) ? "https://localhost:8080/batchQuery-all.json" : ((points == 5) ? "https://localhost:8080/batchQuery-five.json" : "https://localhost:8080/batchQuery-six.json") fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. newData = newData.map(obj => { obj.icon = decodeURIComponent(obj.icon); return(obj) }); iconApp.iconList = newData; // the page update right away with new data. }); }); } </script>
Here is one display of icons that have been fetched from the server:
The data being sent is an array with the following kind of structure:
{ "style" : { "color" : "red", "backgroundColor" : "yellow" }, "icon" : svg1, "name" : "thermos" },
ここで、 svg1
はファイルから取得したSVGです。 もちろん、正当なサーバーはデータベースから構造を取得し、SVGが構造に格納されます。
上記のコードのスニペットを次に示します。 これは、JSONをフェッチし、構造体の配列をVueアプリに配置するコードです。 使用中のfetch
のpromise構造を確認できます。 テキストが解析され、次の行で、エンコードされたSVGがデコードされます。 もう1行、Vueがページを更新します。 ボタンバーのボタンの数は、JSON配列の長さと同じになります。
fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. newData = newData.map(obj => { obj.icon = decodeURIComponent(obj.icon); return(obj) }); // the page update right away with new data. iconApp.iconList = newData; }); });
さて、あと2つのスニペット。 Vueアプリ。 読者は、 @click
ディレクティブがボタンに含まれていることに気付くでしょう。 データ要素iconEntry.name
は、引用符で囲まれたメソッドに渡されます。
メソッドはVueアプリ内で定義されています:
<div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div>
これがメソッドの定義のスニペットです。 methods
オブジェクトは、アプリパラメータオブジェクト内のdata
オブジェクトの直後に追加されます。
, methods: { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } }
読者はgoGetPanel
定義を見つける必要があり、 @click
ハンドラーでその使用が指摘されています。 最終的なアプリケーションでは、 alert
呼び出しをサーバーからパネルをフェッチする関数に置き換えることができます。
IoTパネル用のコンポーネントライブラリ
サーバーからフェッチするパネルはHMTLまたはSVG図面であると判断することもできますが、多くの種類のパネルがある場合は、コンポーネントのライブラリを使用することで、パネルの作成作業を簡素化できると期待しています。から選ぶ。 SVGエディターを改善して、編集の一部としてライブラリコンポーネントを画像にドロップできるようにすることができると想像できます。 次に、SVGエディターがコンポーネントタグ付きの画像のバージョンを出力できる場合、Vueを使用すると、JavaScriptの自動化とアニメーションがきちんと織り合わされていることを確認しながら、画像を作成できます。 私たちの議論では、手作業で編集することでそこにたどり着くことができます。
Vueコンポーネントからパネルを作成したい場合は、コンポーネントを作成する方法を理解し、それらをまとめて有用なものにする方がよいでしょう。 Vueが提供するコマンドラインツールの使用に切り替えて、ワークフローを整理する必要があります。
コンポーネント
Vueのドキュメントでは、コンポーネント定義のコンポーネントdata
セクション(サブオブジェクト)は、データを返す関数である必要があると指摘されています。 これは、Vueがインスタンス間でデータを分離しておく必要があるためです。 したがって、Vueアプリケーションの初期化からコンポーネント定義に移行する際に、別の小さなコード変更があります。
この最初のコードスニペットでは、Vueアプリケーションが初期化されています。
var iconApp = new Vue({ el: '#iconApp', data: { // this is the data field that can be easily updated }, methods : { ... } });
この新しいコードスニペットでは、コンポーネントが定義および登録されています。 まず、 new Vue
インスタンスを作成する代わりに、 iconic
という名前のコンポーネントが登録されていることに注意してください。 次に、 data
フィールドは、Vueアプリが作成するiconic
インスタンスのカスタムデータを返します。 最後に、 template
フィールドはコンポーネント登録の最後にあります。 コンポーネントを表示するためにWebページに記述された可能性のあるHTMLは、 template
の一部にすることができます。
Vue.component('iconic', data: () => { var instanceData = { // data fields named for the // variables appearing in the template onevar : "test" } return(instanceData); }, methods : { ... }, template: '<div>This appears in every instance {{onevar}}</div>' });
だから、温度計付きのパネルを想像することができます。 したがって、誰かがthermometer
コンポーネントを提供した場合、コードのどこかにコンポーネント定義が必要になります。 そのような:
Vue.component('thermometer', data: () => { var instanceData = { // data fields named for the // variables appearing in the template temperature : 0 } return(instanceData); }, methods : { ... }, template: '<div>Some SVG will go here</div>' });
次のようなものを作成しようとしています。
温度計のコンポーネントは、Vueチュートリアルで出くわす最初のコンポーネントと非常によく似ています。 ただし、更新方法を理解するのは少し難しいです。 プロパティを使用して反応性のコンポーネントを定義するより良い方法があります。 そして、それは次のとおりです。
Vue.component('thermometer', { props: ['temperature'], computed : { y: function() { var t = this.temperature/100; var h = 54.724472; var y_bar = 41.176476 // starts near the top // pretend the scale is 1 to 100, so that the temperature is a precentage return((1 - t)*h + y_bar) }, height : function() { var t = this.temperature/100; var h = 54.724472; // as high as the whole range var y_bar = 41.176476 // pretend the scale is 1 to 100, so that the temperature is a precentage return(t*h) } }, template: '#thermometer-template' })
したがって、温度をデータ要素として表す代わりに。 これは、 props
の下のプロパティとして表されます。 次に、プロパティの関数である変数を提供する、計算された新しいセクションがあります。 this.temperature
がy
とheight
の両方に使用されていることがわかります。 これらの計算された変数は、SVGで長方形の属性として使用されています。
SVGでは、 y
は上から下に向かって大きくなります。 したがって、温度計の下部にある長方形を小さくする場合は、赤いボックスのy
を低くし、( y + height
)が温度計のゼロに留まるように高さを低くする必要があります。
コンポーネントの定義のtemplate
フィールドに注意してください。 実際には、ドキュメント要素IDです。 参照されている要素は、特別なタイプのスクリプトセクションです: type="text/x-template"
。 スクリプト要素は、温度計のSVGがある場所です。 また、SVGはVue変数と制御項を利用して、反応度を定義できるようにします。
SVGの一部を次に示します。
<script type="text/x-template"> <svg xmlns:svg="https://www.w3.org/2000/svg" xmlns="https://www.w3.org/2000/svg" width="20" height="70" version="1.1" > <g transform="translate(0,-180)"> <g transform="matrix(2.0111869,0,0,1.0489665,-215.11053,144.5592)"> <rect stroke-linecap="null" stroke-linejoin="null" width="2.9665921" height="54.724472" x="111.90748" y="41.176476" /> <rect stroke-linecap="null" stroke-linejoin="null" width="2.9665921" x="111.90748" :height="height" :y="y" /> <g transform="matrix(0.76503813,0,0,1,26.586929,0)"> <line y2="57.306953" y1="57.306953" x2="113.15423" x1="107.22105" stroke-linejoin="null" stroke-linecap="null" /> <line y2="74.408356" y1="74.408356" x2="113.15423" x1="107.22105" stroke-linejoin="null" stroke-linecap="null"
読者は上部にid="thermometer-template"
を見つけることができ、さらにrect
要素を見下ろすと、計算された変数を見つけることができます。
ここでは、変数の使用が分離されています。 v-bind
のVue省略構文が使用されており、 :height="height"
で、 y
:と同じです。
x="111.90748" :height="height" :y="y"
SVG要素の親が温度計プロパティtemperature
への入力として機能する変数を設定すると、Vueはheight
とy
を再計算します。 その結果、赤いボックスの位置と高さが変わります。
温度計を利用するVueアプリのリストを作成すると便利です。
<body> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Set Temperature</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button @click="updateTemp(50,50)">mid</button> <button @click="updateTemp(20,80)">low</button> <button @click="updateTemp(80,20)">high</button> </div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> <script> var thermoApp = new Vue({ el: '#thermoApp', data: { temp1 : 30, temp2 : 60, queryToken : "HEAT" }, methods : { updateTemp: function (tval1,tval2) { this.temp1 = tval1; this.temp2 = tval2; } } }); </script> </body>
それがすべてです。 thermoApp
アプリケーションのupdateTemp
メソッドを呼び出す3つのボタンがあります。 データセクションには2つの温度変数があります。 また、各thermometer
は値が変わると温度を更新します。
以下に示す2つの温度計のコードは、Vueアプリに割り当てられたHTMLにあります。
<thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer>
アプリケーションがメソッド定義にfunction
形式を使用していることに注意してください。 updateTemp
このように定義するとupdateTemp: function (tval1,tval2)
により、インスタンス変数this
にアクセスできるようになります。
また、このようにupdateTemp
を定義すると、 updateTemp: (tval1,tval2) =>
は、 this
を反応せずにビューを更新する内部データ構造に割り当てます。
パネルの組み立て
各IoTパネルをコンポーネントにすることができます。 Vueは、サブコンポーネントを使用してコンポーネントを定義する方法を提供します。 または、任意のHTMLコンテンツをラップアラウンドできるコンポーネントを生成するために使用できるスロットメカニズムがあります。
次のいくつかの段落では、サブコンポーネントからパネルを作成する方法を見てみましょう。 私たちの例からすぐに続く2つの形式があります。 あるケースでは、温度計はJavaScriptで呼び出されるサブコンポーネントにすることができます。 別のケースでは、コンポーネントは独立して定義されていますが、HTMLで言及されています。
どちらの場合も、同じHTMLをテンプレートに使用できます。 テンプレートとしてのパネルは次のとおりです。
<script type="text/x-template"> <div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> </script>
アプリケーションの最初の詳細の唯一の違いは、 div
要素が2つの温度計を囲んでいることです。 テンプレートに最上位のDOM要素がない場合、Vueはエラーをスローします。 div
はVue要件に合格し、複数の要素がその中に含まれる場合があります。
これで、2つの温度計が並んで表示される場合があります。 温度を上から最後の温度計に渡すと、値がカスケードされます。 トップレベルでは、アプリケーションDOMに1行が含まれている場合、パネルはアプリケーションに参加します。
<themo-panel :temp1="temp1" :temp2="temp2" ></themo-panel>
パネルのテンプレートは、シンプルではありますが、コンポーネントの観点からパネルを簡単に設計できることを示しているようです。 まるでIoTコンポーネントだけの言語が可能であるかのようです。
これで、パネルのテンプレート定義は十分に単純になりました。 これは、独立して定義されたサブコンポーネントを使用したものです。
Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template' });
これは、パネルを機能させるために必要な量とほぼ同じです。 このバージョンは、メッセージがページに入ったときに更新される値を定義するために、プロパティの長いリストに依存していることは事実です。 しかし、これは良いスタートです。 トップレベルでdata
オブジェクトを更新すると、温度計をアニメーション化できます。 ただし、パネルが複雑になると、変化を示す別の方法が必要になる場合があります。
サブコンポーネントを指定する他の方法について言及したので、パネルについては、それを確認する必要があります。 ここにあります:
Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template', components: { // a sub component for the labels 'thermometer': { props: { temperature: Number, }, template: '#thermometer-template', computed : { y: function() { var t = this.temperature/100; var h = 54.724472; var y_bar = 41.176476 // starts near the top // pretend the scale is 1 to 100, so that the temperature is a precentage return((1 - t)*h + y_bar) }, height : function() { var t = this.temperature/100; var h = 54.724472; // as high as the whole range var y_bar = 41.176476 // pretend the scale is 1 to 100, so that the temperature is a precentage return(t*h) } } } } });
確かにもっと多くのコードがありますが、それはthermometer
コンポーネントのJavaScriptがthermo-panel
のコンポーネントリストに含まれているためです。 2つのアプローチは同じ仕事をしますが、コンポーネント定義をパッケージ化する方法が異なります。
現時点では、私の好みは最初の方法です。 テンプレートとプロパティを変更するだけでよい場合は、パネルを修正して動的に取得する方がはるかに簡単です。 この目的のために、独立して定義されたコンポーネントがコンポーネントライブラリを形成します。 しかし、それは良いように思えますが、以下では、2番目の、一見冗長な方法を使用する方が便利になります。
明確に定義された方法でコンポーネントからレスポンシブパネルを作成できることを前提として、次の記事では、簡単なクエリを実行できるデータベースとしてそれらを管理する方法について説明します。