記事の内容
概要
transition-groupは、リストアイテムの追加・削除や順序変更に対してアニメーションを適用するために使用されます。
list
フェードイン・フェードアウト、スライドイン・スライドアウト、スケール、回転などのアニメーションが適用されます。
list
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>リッチなトランジショングループアニメーション</title>
<link rel="stylesheet" href="main.css" />
</head>
<body class="app-body">
<div id="app" class="app-container">
<button @click="addItem" class="btn">追加</button>
<button @click="removeItem" class="btn">削除</button>
<transition-group name="list" tag="p">
<span v-for="item in items" :key="item" class="list-item">
{{ item }}
</span>
</transition-group>
</div>
<!-- CDN -->
<script src="CDNのURL"></script>
<script src="main.js"></script>
</body>
</html>
Vue.createApp({
data() {
return {
items: [1, 2, 3, 4, 5],
};
},
methods: {
addItem() {
this.items.push(this.items.length + 1);
},
removeItem() {
this.items.pop();
},
},
}).mount("#app");
.app-body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.app-container {
text-align: center;
}
.btn {
padding: 10px 20px;
margin: 10px;
background-color: #3498db;
border: none;
border-radius: 5px;
color: white;
cursor: pointer;
font-size: 16px;
}
.btn:hover {
background-color: #2980b9;
}
.list-item {
display: inline-block;
margin: 10px;
padding: 20px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: all 0.5s;
}
/* フェードイン・フェードアウト */
.list-enter-active,
.list-leave-active {
transition: opacity 0.5s, transform 0.5s;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateY(30px) scale(0.5) rotateY(180deg);
}
/* スライドイン・スライドアウト */
.list-enter-active,
.list-leave-active {
transition: transform 0.5s;
}
.list-enter-from,
.list-leave-to {
transform: translateX(30px);
}
/* バウンスアニメーション */
.list-move {
transition: transform 0.5s;
}
出力結果
flip-list
リストアイテムがY軸で回転して表示され、動的で視覚的に魅力的です。
flip-list
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>リッチなトランジショングループアニメーション</title>
<link rel="stylesheet" href="main.css" />
</head>
<body class="app-body">
<div id="app" class="app-container">
<button @click="addItem" class="btn">追加</button>
<button @click="removeItem" class="btn">削除</button>
<transition-group name="flip-list" tag="p">
<span v-for="item in items" :key="item" class="list-item">
{{ item }}
</span>
</transition-group>
</div>
<!-- CDN -->
<script src="CDNのURL"></script>
<script src="main.js"></script>
</body>
</html>
Vue.createApp({
data() {
return {
items: [1, 2, 3, 4, 5],
};
},
methods: {
addItem() {
this.items.push(this.items.length + 1);
},
removeItem() {
this.items.pop();
},
},
}).mount("#app");
.app-body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.app-container {
text-align: center;
}
.btn {
padding: 10px 20px;
margin: 10px;
background-color: #3498db;
border: none;
border-radius: 5px;
color: white;
cursor: pointer;
font-size: 16px;
}
.btn:hover {
background-color: #2980b9;
}
.list-item {
display: inline-block;
margin: 10px;
padding: 20px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: all 0.5s;
}
/* Flip List アニメーション */
.flip-list-enter-active,
.flip-list-leave-active {
transition: all 0.5s;
}
.flip-list-enter-from,
.flip-list-leave-to {
transform: rotateY(180deg);
opacity: 0;
}
/* バウンスアニメーション */
.flip-list-move {
transition: transform 0.5s;
}
出力結果
list-complete
リストアイテムの追加、削除、並べ替え時に滑らかな移動アニメーションが適用されます。
list-complete
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>リッチなトランジショングループアニメーション</title>
<link rel="stylesheet" href="main.css" />
</head>
<body class="app-body">
<div id="app" class="app-container">
<button @click="addItem" class="btn">追加</button>
<button @click="removeItem" class="btn">削除</button>
<transition-group name="list-complete" tag="p">
<span v-for="item in items" :key="item" class="list-item">
{{ item }}
</span>
</transition-group>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.prod.js"></script>
<script src="main.js"></script>
</body>
</html>
Vue.createApp({
data() {
return {
items: [1, 2, 3, 4, 5],
};
},
methods: {
addItem() {
this.items.push(this.items.length + 1);
},
removeItem() {
this.items.pop();
},
},
}).mount("#app");
.app-body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.app-container {
text-align: center;
}
.btn {
padding: 10px 20px;
margin: 10px;
background-color: #3498db;
border: none;
border-radius: 5px;
color: white;
cursor: pointer;
font-size: 16px;
}
.btn:hover {
background-color: #2980b9;
}
.list-item {
display: inline-block;
margin: 10px;
padding: 20px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: all 0.5s;
}
/* List Complete アニメーション */
.list-complete-enter-active,
.list-complete-leave-active {
transition: all 0.5s;
}
.list-complete-enter-from,
.list-complete-leave-to {
transform: translateY(30px);
opacity: 0;
}
/* Move animation for sorting */
.list-complete-move {
transition: transform 0.5s;
}
出力結果
staggered-fade
各アイテムが順番にフェードイン・フェードアウトしながら表示されます。
staggered-fade
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>リッチなトランジショングループアニメーション</title>
<link rel="stylesheet" href="main.css" />
</head>
<body class="app-body">
<div id="app" class="app-container">
<button @click="addItem" class="btn">追加</button>
<button @click="removeItem" class="btn">削除</button>
<transition-group name="staggered-fade" tag="p">
<span v-for="item in items" :key="item" class="list-item">
{{ item }}
</span>
</transition-group>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.prod.js"></script>
<script src="main.js"></script>
</body>
</html>
Vue.createApp({
data() {
return {
items: [1, 2, 3, 4, 5],
};
},
methods: {
addItem() {
this.items.push(this.items.length + 1);
},
removeItem() {
this.items.pop();
},
updateIndexes() {
this.$el.querySelectorAll(".list-item").forEach((el, index) => {
el.style.setProperty("--index", index);
});
},
},
mounted() {
this.$nextTick(() => {
this.updateIndexes();
});
},
updated() {
this.updateIndexes();
},
}).mount("#app");
.app-body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.app-container {
text-align: center;
}
.btn {
padding: 10px 20px;
margin: 10px;
background-color: #3498db;
border: none;
border-radius: 5px;
color: white;
cursor: pointer;
font-size: 16px;
}
.btn:hover {
background-color: #2980b9;
}
.list-item {
display: inline-block;
margin: 10px;
padding: 20px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: all 0.5s;
}
/* Staggered Fade アニメーション */
.staggered-fade-enter-active,
.staggered-fade-leave-active {
transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
}
.staggered-fade-enter-from,
.staggered-fade-leave-to {
opacity: 0;
transform: translateY(30px);
}
.staggered-fade-enter-active .list-item {
transition-delay: calc(0.1s * var(--index));
}
.staggered-fade-leave-active .list-item {
transition-delay: calc(0.1s * var(--index));
}
出力結果