Vue.jsでフォトギャラリーサイト作ってみた
はじめに
BiSのライブ楽しすぎ🏖
→記録に残したい
→フィルムカメラ購入
→撮った写真をweb上でまとめたい
→レンダリングは少なくしたい
→Vue.js
という流れでフォトギャラリーサイトを作ってみました。↓
全体像
全体の見た目はこんな感じです。PC表示だとなんか間延びしてるなーと感じるので今後改良していきたいと思います。
サイト名とロゴ
まずサイト名ですがVue×BiSということでv-BiSというvueのディレクティブのような名前にしました。
ロゴはいくつか作った結果、大好きなファッションブランドのPOLYを参考にしたものにしました。
楕円形は昔の企業ロゴみたいでかわいいですね。POLYのインスタ↓
お手軽にInstagram APIを叩く
ヘッダーの下にある正方形の画像群は普段インスタに投稿しているマッシュアップ画像です。
当初はInstagram APIを自分で叩いて実装しようと考えていたんですが、facebookのアカウントを作らなければいけなかったりと色々難しそうだったので神サービス「LightWidget」を使いました。
GUIが優秀で、レイアウトやアニメーションを直感的に設定できるのでオススメです。
写真の表示とフィルター
その下に、メンバーごとの写真に切り替えるフィルターボタンを作りました。
フォトギャラリーは必然的に画像が多く重くなりがちなので単一ページ内で切り替えを行うようにしてます。
<div class="members">
<transition appear name="menu1">
<div class="member bis" v-bind:class="{ active: memberFilter === 'BiS' }" v-on:click="setMember('BiS')">
BiS</div>
</transition>
<transition appear name="menu3">
<div class="member chamo" v-bind:class="{ active: memberFilter === 'CHANTMONKEE' }"
v-on:click="setMember('CHANTMONKEE')">🐵 CHANTMONKEE 🐵</div>
</transition>
<transition appear name="menu4">
<div class="member neo" v-bind:class="{ active: memberFilter === 'NEOTREES' }"
v-on:click="setMember('NEOTREES')">🌲 NEOTREES 🌲</div>
</transition>
<transition appear name="menu6">
<div class="member nano" v-bind:class="{ active: memberFilter === 'NANO3' }" v-on:click="setMember('NANO3')">
🌷 NANO3 🌷</div>
</transition>
</div>
<script>
new Vue({
el: '#app',
data: {
memberFilter: 'BiS',//初期表示
projects: [
{ title: "", image: "https://raw.githubusercontent.com/v-bis/top/main/nano5.jpg" , category:'NANO3'},
{ title: "", image: "https://raw.githubusercontent.com/v-bis/top/main/neo2.jpg" , category:'NEOTREES'},
{ title: "", image: "https://raw.githubusercontent.com/v-bis/top/main/mon3.jpg" , category:'CHANTMONKEE'},
]
},
methods: {
setMember: function (member) {
this.memberFilter = member;
}
}
})
</script>
↑上記のコードは多少省略してますが、まず写真にcategory(メンバーの名前)を仕込んでおき、各メンバーのボタンをクリックしたらactiveになって写真が切り替わるという感じです。
初期表示は、memberFilter: 'BiS'にしているのでBiSのボタンを押すと、フィルターが解除されすべての写真が表示されます。
↓写真を表示させている箇所
<transition-group class="projects" name="projects">
<div class="project" v-if="memberFilter === project.category || memberFilter === 'BiS'" v-bind:key="project.title"
v-for="project in projects">
<div class="project-image-wrapper">
<img class="project-image" v-bind:src="project.image">
<div class="gradient-overlay"></div>
</div>
</div>
</transition-group>
フィルターボタンの実装はこちらを参考にさせていただきました。こちらを読んだほうが遥かにわかりやすいです。
また、できるだけ写真の表示を軽くするためにcontent-visibilityプロパティで遅延読み込みをさせています。かなり便利。
.project-image-wrapper img {
content-visibility: auto;
contain-intrinsic-size: 350px;
}
デザインについて
最近、和洋折衷ならぬ新旧折衷にハマっています。
流行や懐古に惑わされず、"各時代の自分がイイと思うもの"をぶちこむのってオリジナルを作ってるって感じでとても楽しいです。
なので今回はフィルム写真という"古さ"を残しつつ彫刻刀で角丸に削り上げてみました。
あと、絵文字を多用してslackっぽくしてみたり、ボタンにグラデーション使ってtiktokっぽくしたりしてます(?)
これからも、たまこまーけっとの「たまや」と「RICE CAKE Oh! ZEE」を合併させたような美味しいお餅をたくさん作っていきたいです。
おまけ
faviconは「ぶ」です。元ネタは、けいおん!のキーホルダー。
フォントはもちろん「けいふぉんと!」です。
追記
ヘッダーにぶち込み
インスタの画像が横いっぱいに広がってるのが間延びしている原因のような気がしたので、ヘッダーの中にぶちこんでみました。これで少しまとまりが出たような気がします。
あとは背景が少しさびしく感じるのでテコ入れしたいのと、フィルムの写真の方にもいい感じのlightboxを実装したいですね。
追記2
意外とデザインは重ねちゃってOKだった
各要素が別れているから間延びするんであって、どんどん重ねてもいいんじゃないかなと思いこんな感じにしてみました。
フィルムが高杉晋作
あとUIには関係無いですがフィルムの高騰がヤバすぎてミラーレスカメラ買いました...
高騰&品薄でいつも使っている富士フィルムのiso400がどこにもなく、試しにKodakのPORTRA400を買ってみたんですが色の鮮やかさがとても良いのでこれから使っていこうと思います。ただ富士フィルムよりもさらに高いので、どのみちフィルムカメラを使うのはここぞというときのみになりそうです。
追記3
vueでテキスト表示
画像がかなり増えてきたので、日付と会場名を左下に記載することにしました。
画像と同様にテキストもvue側で記載をして{{ project.title }}でHTMLに表示させる形です。
配色はNuxt.jsの公式サイトを参考にしました。
<transition-group class="projects" name="projects">
<div class="project" v-if="memberFilter === project.category || memberFilter === 'BiS'"
v-bind:key="project.title" v-for="project in projects">
<div class="project-image-wrapper">
<img class="project-image" v-bind:src="project.image">
<div class="gradient-overlay"></div>
<span class="image-text">{{ project.title }}</span>
</div>
</div>
</transition-group>
<script>
new Vue({
el: '#app',
data: {
memberFilter: 'BiS',//初期表示
projects: [
{ title: "22.03.12 MORIOKA CLUB WAVE", image: "https://raw.githubusercontent.com/v-bis/top/main/mon2.webp", category: 'CHANTMONKEE' },
]
},
methods: {
setMember: function (member) {
this.memberFilter = member;
}
}
})
</script>
.image-text {
position: absolute;
font-size:10px;
bottom:10px;
left: 0px;
transform-origin: top right;
color: #fff;
padding: 5px;
padding: 10px 5px;
font-weight: bold;
background: #40b88290;
font-family: monospace;
text-align: center;
writing-mode: vertical-rl;
text-orientation: sideways;
z-index: 99;
opacity: 0;
animation: fadeIn 7s ease-in-out forwards;
border-radius: 15px 15px 0px 15px;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
70% {
opacity: 0;
}
100% {
opacity: 1;
}
}
フィルムが高杉晋作2
あとUIには関係無いですがフィルムの高騰がヤバすぎてフィルムカメラ売ろうかなと思っています...
この間買ったミラーレスカメラ(SONYα6400)はかなりいい感じなので、売ったお金で単焦点レンズを買って多肉植物とか撮りたいですね。
Webpで軽量化
いままでjpgで書き出してたんですがさすがに画像の枚数が多くなってきたのでWebpに全部変換しました。気休め程度かなと思っていたらかなりサクサク動くようになったので、Z世代に絶大な人気を誇る次世代フォーマットは伊達じゃありませんね...
次にやりたいこと
次はZennさんの目次のような、スクロールに追随して反応するナビゲーションを実装して時系列をもっと見やすくできればなと思っています。最近はWikipediaでも使われていますがめちゃくちゃ見やすいですね。
Discussion