溝畑です。
KP内では珍しくフロントエンドばかり触ってる人間です。
開発ブログを書くのは久々。
ネタはないことないんですけど、なかなか書くまでいかない。。。
前回はVimのテキストオブジェクトネタでしたっけ・・・?
今回はVueのお話です。多分ここで書くのは初めてだと思います。
フロントエンドあるあるだと思うんですが、Chromeの拡張でReactとかVueのを入れている関係で、
「あっ、このサービスはこのFW使ってるんだ!」っていうやつ。
dev-tool開いて、Element見ながら「このclass名なんだろう?」みたいなことをして、
使ってるライブラリやプラグインを特定して自分でも試してみたり。
そんなこんなで触ってみたvue-grid-layoutのお話です。
vue-grid-layout
vue-grid-layoutは、React-Grid-Layoutにインスパイアされて作られているものです。Gridster.jsライクなもので、自由にドラッグしてコンテンツの大きさを変えたり、配置を変えたりするUIが簡単に作れます。
早速サンプル見ていきましょう。
基本
正直、DocumentのExamples見た方が早いので、Examples参照してください。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<div id="app"> <grid-layout :layout.sync="layout" :col-num="12" :row-height="30" :is-draggable="true" :is-resizable="true" :vertical-compact="true" :use-css-transforms="true" > <grid-item v-for="item in layout" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" > {{ item.i }} </grid-item> </grid-layout> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const layout = [ { x:0, y:0, w:2, h:2, i:"0" }, { x:2, y:0, w:2, h:4, i:"1" }, { x:4, y:0, w:2, h:5, i:"2" } ] new Vue({ el: "#app", data() { return { layout } } }) |
これだけでドラッグして動かして、大きさも変えられるUIが作れます。
簡単ですね。
jsfiddle -> vue-grid-layout sample
Fiddle置いておくので、触って、コードいじって遊んでみてください。
コンポーネントの描画
実際にこれを使っていくとすると、grid-itemの中には各種コンポーネントが入ってくるはずです。1つのコンポーネントをv-forでループして描画するのであれば、grid-itemの中で、そのコンポーネントを書けばOKです。
(以下、説明用にprops省略して書いていきます)
1 2 3 4 5 |
<grid-layout> <grid-item v-for="item in layout"> <hoge-component/> </grid-item> </grid-layout> |
ですが、このパターンはほとんどなくて、それぞれのgrid-itemには別のコンポーネントを描画したいはず。
Vueには動的なコンポーネントの描画方法があります。
動的なコンポーネント
1 2 3 4 5 |
<grid-layout> <grid-item v-for="item in layout"> <component :is="item.i"/> </grid-item> </grid-layout> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import FooComponent from 'Foo.vue' import HogeComponent from 'Hoge.vue' import PiyoComponent from 'Piyo.vue' const layout = [ { x:0, y:0, w:2, h:2, i:"FooComponent" }, { x:2, y:0, w:2, h:4, i:"HogeComponent" }, { x:4, y:0, w:2, h:5, i:"PiyoComponent" } ] new Vue({ el: "#app", components: { FooComponent, HogeComponent, PiyoComponent }, data() { return { layout } } }) |
layoutのiにコンポーネント名を書いておき、:isに入れてあげると簡単です。
レイアウトの保持
"レイアウトの保持"は、この手のUIを提供すると、必ず要望として上がってくるでしょう。実現方法としては単純で、layout-updatedイベントでlocalStorageにlayoutを保持してあげればOKです。
1 2 3 |
<grid-layout @layout-updated="layoutUpdated"> <!-- html... ---> </grid-layout> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
const defaultLayout = [ // layout ] new Vue({ el: "#app", data() { return { layout: defaultLayout } }, created() { if (localStorage.getItem('app-layout')) { this.layout = JSON.parse(localStorage.getItem('app-layout')) } else { this.layout = defaultLayout } }, methods: { layoutUpdated(newLayout) { localStorage.setItem('app-layout', JSON.stringify(newLayout)) } } }) |
こんなイメージです。
まとめ
vue-grid-layoutを使うと、簡単にこのようなUIが作れます。使ってみての感想ですが、サイズを変えられるという特性上、中に描画するコンポーネントは、
ある程度サイズの変更に耐えられるようにする必要が生じるなという印象です。
細かくレイアウトを指定されるような案件だと、逆に面倒なことになるかもしれません。
ざっくりで良ければ、display: flexとflex-wrap: wrapでどうにかなるかもしれませんが・・・。
グラフ(Highcharts)や地図(OpenLayers)などを描画している場合は、resizedのタイミングで、それ自体のサイズを変更する必要もあります。
grid-item自体のサイズをとって・・・resizeをかけるようなイメージ。
使い始めて間もないので、Tipsがたまればまた書きます。
それでは。