vue3 に aos を適用しアニメーションさせる
2024/04/29 12:00:00
前提 #
- 動作環境は git-bash とする
構築手順は以下を参考にする
https://blog.oya3.net/posts/2023/10/03/00_git/ - node21 + vite5 + vue3 + bootstrap5 + sass を使用する
構築手順は以下を参考にする
http://blog.oya3.net/posts/2024/04/27/vite-vue-bootstrap-sass/ - aos で以下を実現する
- カードを絞り込む
aos をインストールする #
$ npm install aos
aos を vue3 で使えるようにする #
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './scss/styles.scss'
import 'animate.css/animate.min.css';
import 'bootstrap-icons/font/bootstrap-icons.css';
import * as bootstrap from 'bootstrap'
import AOS from 'aos' // 追加
import 'aos/dist/aos.css' // 追加
const app = createApp(App)
app.use(router)
app.use(AOS.init()) // 追加
app.mount('#app')
カードを絞り込む #
- 絞り込むカテゴリ一覧を設定
<template> ... <div class="container" data-aos="fade-up" data-aos-delay="200"> <button v-for="(category,index) in categories" :key="index" :filter="category.name" :class="{ active: activeIndex === index }" class="btn btn-outline-secondary btn-sm m-2" @click="changeCategory($event,index)">{{category.title}} </button> </div> ... </template> <script setup> ... const categories = ref([ { 'name': 'All', 'title': 'すべて', }, { 'name': '血液検査', 'title': '血液検査', }, { 'name': '生化学検査', 'title': '生化学検査', }, { 'name': 'C', 'title': 'C', }, { 'name': 'D', 'title': 'D', }, ]); ... </script>
- 絞り込み対象のカード一式を設定
<template> ... <div class="container" data-aos="fade-up" data-aos-delay="500"> <div class="grid"> <div v-for="item in items" class="item" :data-category="item.category"> <div class="item-content"> <img :src="item.image" style="width:100%;height:100%;"> <div class="card-body"> <p class="card-title">{{item.name}}</p> <div class="card-text">{{item.docs}}</div> <a :href="item.link" class="btn btn-primary btn-sm" role="button">詳細</a> </div> </div> </div> </div> </div> ... </template> <script setup> ... const items = ref([ { category: '血液検査', name: 'EYM-230 動物用', docs: '', image: image_01, link: '/productions/01', }, { category: '血液検査', name: '全自動血球計数装置 PCE-350', docs: '', image: image_02, link: '/productions/01', }, { category: '血液検査', name: '全自動血球計数装置 EYM-230', docs: '', image: image_03, link: '/productions/01', }, { category: '生化学検査', name: 'マイクロフローセル生化学分析装置 AE-600F(フィルター式)', docs: '', image: image_04, link: '/productions/01', }, { category: '生化学検査', name: 'マイクロフローセル生化学分析装置 AE-600P(分光式)', docs: '', image: image_04, link: '/productions/01', }, ]); ... </script>
- その他js設定
const muuriGrid = ref(null); // Muuri インスタンスを格納するための ref const activeIndex = ref(0); onMounted( async () => { muuriGrid.value = new Muuri('.grid', { }); }); const changeCategory = (event, index) => { var category = event.target.getAttribute('filter'); activeIndex.value = index; if(category == 'All'){ muuriGrid.value.filter('*'); } else{ muuriGrid.value.filter(`.item[data-category="${category}"]`); } };
以下、サンプルコードまとめ
$ emacs src/components/home.vue
<template>
<Header />
<div class="container" data-aos="fade-up" data-aos-delay="200">
<button v-for="(category,index) in categories"
:key="index"
:filter="category.name"
:class="{ active: activeIndex === index }"
class="btn btn-outline-secondary btn-sm m-2"
@click="changeCategory($event,index)">{{category.title}}
</button>
</div>
<div class="container" data-aos="fade-up" data-aos-delay="500">
<div class="grid">
<div v-for="item in items" class="item" :data-category="item.category">
<div class="item-content">
<img :src="item.image" style="width:100%;height:100%;">
<div class="card-body">
<p class="card-title">{{item.name}}</p>
<div class="card-text">{{item.docs}}</div>
<a :href="item.link" class="btn btn-primary btn-sm" role="button">詳細</a>
</div>
</div>
</div>
</div>
</div>
<Footer />
</template>
<script setup>
import { onMounted, ref } from 'vue';
import 'web-animations-js';
import Muuri from 'muuri';
import Header from './Header.vue'
import Footer from './Footer.vue'
import image_01 from '@/assets/images/portfolio/portfolio-1.jpg'
import image_02 from '@/assets/images/portfolio/portfolio-2.jpg'
import image_03 from '@/assets/images/portfolio/portfolio-3.jpg'
import image_04 from '@/assets/images/portfolio/portfolio-4.jpg'
import image_05 from '@/assets/images/portfolio/portfolio-5.jpg'
// const pageName = ref('test');
// const grid = ref(null);
const categories = ref([
{
'name': 'All',
'title': 'すべて',
},
{
'name': '血液検査',
'title': '血液検査',
},
{
'name': '生化学検査',
'title': '生化学検査',
},
{
'name': 'C',
'title': 'C',
},
{
'name': 'D',
'title': 'D',
},
]);
const items = ref([
{
category: '血液検査',
name: 'EYM-230 動物用',
docs: '',
image: image_01,
link: '/productions/01',
},
{
category: '血液検査',
name: '全自動血球計数装置 PCE-350',
docs: '',
image: image_02,
link: '/productions/01',
},
{
category: '血液検査',
name: '全自動血球計数装置 EYM-230',
docs: '',
image: image_03,
link: '/productions/01',
},
{
category: '生化学検査',
name: 'マイクロフローセル生化学分析装置 AE-600F(フィルター式)',
docs: '',
image: image_04,
link: '/productions/01',
},
{
category: '生化学検査',
name: 'マイクロフローセル生化学分析装置 AE-600P(分光式)',
docs: '',
image: image_04,
link: '/productions/01',
},
]);
// const filter = ref('A'); // フィルタリングするカテゴリ
const muuriGrid = ref(null); // Muuri インスタンスを格納するための ref
const activeIndex = ref(0);
onMounted( async () => {
muuriGrid.value = new Muuri('.grid', {
// dragEnabled: true
});
// window.addEventListener('load', function () {
// muuriGrid.value.refreshItems().layout();
// });
// await nextTick();
// AOS.init({
// startEvent: 'load',
// once: true,
// });
});
const changeCategory = (event, index) => {
var category = event.target.getAttribute('filter');
activeIndex.value = index;
if(category == 'All'){
muuriGrid.value.filter('*');
}
else{
muuriGrid.value.filter(`.item[data-category="${category}"]`);
}
};
</script>
<style lang="scss" scoped>
.grid {
/* position: relative; */
}
.item {
display: block;
position: absolute;
/* z-index: 1; */
width: 270px;
height: 270px;
background-size: cover;
margin: 20px 60px;
}
.card-body {
position: absolute;
bottom: 0;
/* padding: 5px; */
top: auto;
/* transform: translateY(50%); */
background-color: rgba(255, 255, 255, 0.85);
/* color: #fff; */
top: 65%;
width: 100%;
height: 35%;
text-align: center;
border: 1px solid rgba(80, 80, 80, 0.2);; /* ボーダーを指定 */
border-radius: 5px; /* 角を丸める */
}
/*
.item.muuri-item-dragging {
z-index: 3;
}
.item.muuri-item-releasing {
z-index: 2;
}
.item.muuri-item-hidden {
z-index: 0;
}
*/
</style>