目次
はじめに
高さ可変のMasonryを作る事になりました。
加えてカテゴリーでフィルターできるようにして欲しいとのことで、目ぼしいMasonryライブラリが見つからず、やむを得ず一部自作することにしました。
フィルター付きのリスト部分をVue.jsで作り、MasonryをjQueryに担当させることにしました。
全部Vue.jsにしたかったのですが、高さが可変という条件があるので、Vue.jsのみで対応ができませんでした。
Vue.jsは事前に高さを取得することができませんからね。
そこでjQueryを使って、Vue.jsのマウント後にMasonryレイアウトすることにしました。
【動画サイズ:1.8MB】
環境
この記事は、以下の管理人の検証環境にて記事にしています。
vue.js | 2.6.10 |
jQuery | 1.11.0 |
waterfall-ligh | 1.3.1 |
導入
管理人が行った、動作確認サンプルを実装するために、以下の手順でソースコードを導入していきます。
このサンプルでは、フィルター付きのMasonryレイアウトを実装します。
step.1 ライブラリの呼び出し
今回はサンプルのデザイン用にBootstrapを使用します。
Masonryレイアウトは、waterfall-light というjQueryのライブラリを使用します。
<!-- Bootstrap --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> <!-- Vue.js--> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script> <!-- jQuery --> <script src="https://code.jquery.com/jquery-1.11.0.min.js"></script> <script src="https://code.jquery.com/jquery-migrate-1.2.1.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/waterfall-light@1.3.1/waterfall-light.min.js"></script>
step.2 JavaScript
mountedとupdated時にMasonryレイアウトを行わせます。
mountedは、マウントしてすぐのタイミングでMasonryレイアウトにします。
updatedは、リストの更新をした時に、再度Masonryレイアウトさせます。
new Vue({ el: '#app', data: { isShow: false, checked: [], category: [ {no:1, title:'category:1'}, {no:2, title:'category:2'}, {no:3, title:'category:3'}, {no:4, title:'category:4'}, {no:5, title:'category:5'}, ], items: [ {id:1, category:1, text:'Some quick example text to bue bulk of the cards content.'}, {id:2, category:5, text:'Some quick example text to build on the card title and make up tntent.'}, {id:3, category:2, text:'Some quick example text to build on the card title and mak title and make up title and make up title and make up e up the bulk of the cards content.'}, {id:4, category:4, text:'Some quick example text to build on the card title and makthe cards content.'}, {id:5, category:2, text:'Some quick example text ulk of the cards content.'}, {id:6, category:3, text:'Some quick example text to build on the card title and make up the bulk of the c title and make up title and make up title and make up ards content.'}, {id:7, category:4, text:'Some quick example text to build on the card title and make u title and make up title and make up p the bulk of the cards content.'}, {id:8, category:3, text:'Some quick example text to build on the card title and make up the bulk of the cards content.'}, {id:9, category:1, text:'Some quick example text to build on the card title and make up the bulk of the cards content.'}, {id:10, category:4, text:'Some quick example text to build on the card title and make up the bulk of th title and make up e cards content.'}, {id:11, category:3, text:'Some quick example text to build on the card title and make up the bulk of the cards content.'}, {id:12, category:2, text:'Some quick example text to build on the card title and make up th title and make up title and make up title and make up e bulk of the cards content.'}, ] }, computed: { getItems: function(){ let self = this; return this.items.filter(function(item){ return (self.checked.length === 0 || self.checked.indexOf(item.category) !== -1); }); } }, mounted:function() { let self = this; $('#box').waterfall({ gap: 10, gridWidth: [0,400,600,800,1200], refresh: 0 }); setTimeout(function(){ self.isShow = true; },0); }, updated:function(){ $('#box').waterfall({ gap: 10, gridWidth: [0,400,600,800,1200], refresh: 500 }); } });
step.3 HTML
BootstrapベースのClassを設定していきます。
v-show="isShow"
を設定して、jQueryのMasonryが起動するまでの、一瞬だけ映るぐちゃぐちゃなレイアウトを隠しておきます。
<main id="app" class="flex-shrink-0"> <div class="container"> <div class="row mt-4 mb-4 justify-content-lg-center bg-light p-2 rounded"> <div class="text-center p-4"> <div class="form-check form-check-inline" v-for="item in category"> <input class="form-check-input" type="checkbox" :value="item.no" v-model="checked" > <label class="form-check-label" for="flexCheckDefault"> {{item.title}}</label> </div> </div> </div> <div id="box" v-show="isShow"> <div v-for="(item, index) in getItems" class="card" ref="waterfall" style="width: 180px;"> <svg class="bd-placeholder-img card-img-top" width="100%" height="180" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#868e96"></rect><text x="50%" y="50%" fill="#dee2e6" dy=".3em">Image cap {{item.id}}</text></svg> <div class="card-body"> <h5 class="card-title">Card title {{item.id}}</h5> <p class="card-text">category:{{item.category}}</p> <p class="card-text">{{item.text}}</p> </div> </div> </div> </div> </main>
デモ