Chapter 05

SpaGoコンポーネントとマークアップ

NoboNobo
NoboNobo
2020.10.30に更新

SpaGoのコンポーネントになれる条件

  • spago.Coreを埋め込んだ構造体であること
  • Render() spago.HTMLメソッドを持つこと
  • Render()メソッドが返す内容は後述のspago.Tagが返す値であること

spago.RenderBody(コンポーネント)に渡せるコンポーネントはもう一つ条件が増える。

  • Render()メソッドが返す最上位のTagは必ずbodyタグで始まること

以下のコードが最小限のRenderBodyに渡せるコンポーネントのコード。

type Component1 struct {
  spago.Core
}
func (c *Component1) Render() spago.HTML {
  return spago.Tag("body", ...)
}

SpaGoのマークアップ記述について

HTMLエレメント生成をGoで書く場合は以下のように書きます。

spago.Tag("タグ名", ...マークアップ)

マークアップに書ける記述

  • spago.Tag("タグ名", ...マークアップ): 親タグノードに子ノードとして追加
  • spago.A("属性名",値): 親タグノードに属性値を付与する
  • spago.AttrMap{"属性名": 値,...}: 親タグノードの属性をまとめてAddしたりRemoveしたりする
  • spago.S(...interfac{}): 任意のStringerを文字列化&連結して文字列にする(属性の値やテキストノードの値に使う)
  • spago.Class("クラス名1 クラス名2"): 親タグノードにclass属性を付与する
  • spago.ClassMap{"クラス名": 真偽,...}: 親タグノードのクラスをまとめてAddしたりRemoveしたりする
  • spago.T("テキスト"): 親タグノードにテキストノードを子ノードとして追加
  • spago.C(コンポーネント): 親タグノードにコンポーネントを子ノードとして追加
  • spago.If(コンディション, マークアップ): コンディションが真の時マークアップが有効になる

HTML like DSL

HTMLっぽい記述をSpaGoで使えるGoのコードに変換するツールがあります。

spago generate -c ComponentName -p pkgName ソースHTMLファイル名

-p pkgNameを省略した場合は「main」がパッケージ名に使われます。
ComponentNameとソースHTMLファイル名は省略できません。

出力するのは ComponentName.Render() spago.HTML メソッドの実装だけです。
出力ファイル名はソースHTMLファイル名の末尾の.html_gen.goに置き換えたファイル名です。

基本のHTMLマークアップ

  • 通常のHTML記述は全て使えます。
  • 値やテキストノードのかわりに{{...}}記述が使えます。
  • @イベント名='{{c.メソッド名}}'にてインベントハンドリングの追加。
  • @='{{...}}'にて Go の記述マークアップの追加(属性マークアップ用)。
  • Go記述でcはコンポーネントインスタンスを指しています。
  • c.FieldValueとするとコンポーネントのフィールドメンバを参照できます。
  • また、c.Method1とするとコンポーネントメソッドを参照できます。
  • もちろん、c.Method1()とするとコンポーネントメソッド読んだ戻り値を参照できます。

2つの特殊タグ

  • <import>
  • <raw>

以上2つの特殊タグがあります。

<import>タグの用途

Goコード生成の時、パッケージ参照をするimport構文にパッケージを追加します。

<import>github.com/myname/myapp/components</import>
<body>
  <raw>spago.C(&components.Component{})</raw>
</body>

これでcomponentsパッケージを参照した記述が書けるようになります。

<raw>タグの用途

  • <raw>spago.C(&components.Component{})</raw>: 子コンポーネントを記述
  • <raw>spago.T(fmt.Sprintf("%v", c.Value))</raw>: テキストノードをGoの文字列関数で記述

事例集

  • c.Width int == 100で属性値にstyle='width:{{c.Width}}px;'とすると「style="width:100px"」相当に展開されます。
  • @click='{{c.OnClick}}'とすると、そのノードに addEventListener("click", c.OnClick)相当になります。
  • @='{{spago.ClassMap{"disabled":c.IsConnect()}}}'と書いた場合、このノードのマークアップに{{}}内の内容がそのまま展開されます。
  • style='{{c.GetStyle("designA")}}'というように引数に文字列指定する時もダブルクオートで囲む必要があるのでその外側のクオートはシングルクオートを使いましょう。

ハマりどころ

  • 慣習としてコンポーネントのレシーバーは「c」としています(守らない場合に不具合が出る可能性があります)。
  • *_gen.goファイルを手で編集してはいけません。
  • {{...}}このブロック内は HTML のエスケープやエンティティは使えません。
  • {{...}}このブロックの内と外でクオートは使い分けること推奨は外がシングルクオート、内がダブルクオートです。
  • レンダリングでエラーになるときは*_gen.goファイルが壊れていることが多いので壊れないよう HTML を修正しましょう。
  • spago generateでは SpaGo マークアップ機能の全てを記述できません。複雑な構造や柔軟な構造をもつマークアップはコンポーネントメソッドの戻り値や SpaGo マークアップを手で書くというのも検討してください。