本記事は Riot.js Advent Calendar 2019 の第15日目の記事です.
Riot.js(以下、riot41)は非常にシンプルかつ軽量で入門の敷居も低く, とても書きやすいコンポーネント指向のUIライブラリです。
今回は, 以下の2つのアプリを riot4 で作ってみましたが, svg のレンダリングでちょっと躓いたのでその知見を書いていきたいと思います。
※riot4 の基本機能の紹介になりますのでご了承ください
作ったもの - バンドラ有り
こちらは ICSメディア さんの サンプル を riot4 で作り直したもの(riot-svg
)になります. 今回は parcel-bundler を利用しました.
- リポジトリ → https://github.com/kkeeth/160916_performance_js_framework/tree/master/riot-svg
- デモ → https://kkeeth.github.io/160916_performance_js_framework/riot-svg/dist/index.html
もう一つ riot-dom
の方はちょっと改造していますので, 見る文にはこちらのほうが楽しいかと思いますw
- リポジトリ → https://github.com/kkeeth/160916_performance_js_framework/tree/master/riot-dom
- デモ
→ https://kkeeth.github.io/160916_performance_js_framework/riot-dom/dist/index.html
作ったもの - バンドラ無し
vuejs
ユーザーなら一度は見たことがあるかもしれませんが, vuejs の公式サンプルを riot4 で作り直したものになります.
- リポジトリ → https://github.com/kkeeth/riot-examples/tree/master/bounds-header
- デモ → https://codesandbox.io/embed/riot4-bounds-header-jstlz
アプリの構成
どちらも同じような躓き方をしていますので, 解説は1つ目のみにします. parcel
を利用しており, こちらの方がより開発者向けかとも思いますので. 説明には関係ないコードは省略しておりますのでご注意ください.
まずはディレクトリ構成です.
./
├ src/
│ ├ main.js
│ ├ particle-data.js
│ └ components/
│ ├ app-components.riot ←親コンポーネント
│ └ particle-components.riot ←子コンポーネント
│
├ public/
│ ├ index.html
│ └ favicon.ico
│
├ node_modules/
├ dist/ ←ビルド結果出力ディレクトリ
├ package.json
└ yarn.lock
main.js
にて親である app-component
を読み込み, グローバルに登録2 せずそのままコンポーネントを作成しマウントしています.
さらに, app-component
から子コンポーネント particle-component
を読み込み, グローバルに登録し, マウントしますが, ここでグローバルへの登録の仕方が2通りあります.
▼1つ目: register
メソッドの利用
一番シンプルな登録方法だと思います. riot 本体の register
メソッドを利用します.
<particle-component /* attributes */ />
<script>
// register メソッドの読み込み
import { register } from 'riot'
// 対象のコンポーネントの読み込み
import ParticleComponent from './particle-component.riot'
// 登録
register('particle-component', ParticleComponent)
</script>
</app-component>
▼2つ目: components
オブジェクトとしてセット
export default
オブジェクトの1要素として登録する方法です. 個人的にはこちらの方が好きです.
<particle-component /* attributes */ />
<script>
// 対象のコンポーネントの読み込み
import ParticleComponent from './particle-component.riot'
export default {
// ここでセット
components: {
ParticleComponent
}
}
</script>
上記の通り2つ目の方法では, 読み込み時の名前は変更可能です. 読み込んだ ParticleComponent
の中身をコンソールに出力してみますと,
このように, name
キーでタグの名前が保持されており, riot4 がこちらを見てよしなにやってくれるからです.
〜閑話休題〜
改めて, 今回のアプリケーションの親・子コンポーネントの構成をご紹介します.
<app-component>
<particle-component
width={ window.innerWidth }
height={ window.innerHeight }
particles={ state.particles } />
<script>
import ParticleComponent from './particle-component.riot'
export default {
components: {
ParticleComponent
}
}
</script>
</app-component>
<particle-component>
<g each={ particle in props.particles }>
<rect
x={ particle.displayX }
y={ particle.displayY }
width="3"
height="3">
</rect>
</g>
</particle-component>
じつはこの書き方だと動作しません.
なぜかと言うと, この状態でマウント・レンダリングすると, 以下のように svg
タグが差し込まれまず, 画面としては画像が表示される部分が真っ白になります.
<div id="root" is="app-component">
<div>
<particle-component width="669" height="613">
<g><rect width="3" height="3" x="118" y="576"></rect></g>
(...以下 g タグが続く)
</particle-component>
</div>
</div>
ちょっと修正
直接的な修正の仕方としては, 以下のように svg
タグを明示的に挿入するやり方です.
<particle-component>
+ <svg>
<g each={ particle in props.particles }>
<rect
x={ particle.displayX }
y={ particle.displayY }
width="3"
height="3">
</rect>
</g>
+ </svg>
+ <style>
+ svg {
+ 100vw;
+ 100vh;
+ }
+ </style>
</particle-component>
これでも動くことは動きます. しかし riot4 の場合コンポーネントを作成すると, カスタムタグ(今回は particle-component
)は消えずにそのままレンダリングされるため, そのカスタムタグで挟むことになってしまうのがイケてない…
これを回避するために, 以下のように修正します.
<app-component>
- <particle-component
+ <svg
+ is="particle-component"
width={ window.innerWidth }
height={ window.innerHeight}
particles={ state.particles } />
<script>
import ParticleComponent from './particle-component.riot'
export default {
components: {
ParticleComponent
}
}
</script>
</app-component>
要は, HTML 標準のタグを riot4 のコンポーネントをして扱うということです. こちらは riot4 の基本機能3であり公式ドキュメントにも記載がありますので, そちらをご参照いただければと思いますー. (過去の俺よ…なんで自分で翻訳しておきながら, この存在を忘れてしまった…)
終わりに
riot4 はとても良い子なので, JavaScript の UI ライブラリで軽量かつ簡単に導入できるものを探しているなら, ぜひ一度検討していただけたら嬉しいです!
ではでは(=゚ω゚)ノ
-
最新の Riot.js のメジャーバージョンが 4 ですので, 明示的に riot4 と呼ぶことにします. ↩