本教學打造出了一個互動式的“彈性面板”界面,使用了 Vue 3 Composition API 和 CSS 的 flexbox 布局和過渡動畫。主要功能如下
該範例 使用 Vue 3 的 Composition API 來實現面板的展開與動畫效果。
setup
函數setup
函數是 Vue 3 Composition API 的核心,用於定義組件的邏輯和狀態。在這裡,我使用 setup
來初始化面板的資料,並定義與面板互動的邏輯。該函數返回的資料和方法會暴露給模板使用。
setup() {
const panels = reactive([
{
class: "panel1",
text1: "Hey",
text2: "Let's",
text3: "Dance",
isOpen: false,
isActive: false,
},
// 其他面板資料
]);
// 其他邏輯
return {
panels,
toggleOpen,
toggleActive,
};
}
reactive 用於創建響應式資料。這裡我使用 reactive 來定義 panels,它是一個包含面板資訊的陣列,每個面板都有對應的 CSS 類別、文本內容,以及控制展開和動畫的狀態變量 isOpen 和 isActive。
const panels = reactive([
{
class: "panel1",
text1: "Hey",
text2: "Let's",
text3: "Dance",
isOpen: false,
isActive: false,
},
// 其他面板
]);
toggleOpen 函數用來切換面板的展開狀態。當使用者點擊某個面板時,對應的面板的 isOpen 屬性會在 true 和 false 之間切換,從而觸發 CSS 過渡效果,改變面板的大小和顯示更多文字。
const toggleOpen = (index) => {
panels[index].isOpen = !panels[index].isOpen;
};
toggleActive 函數用來在 CSS 過渡結束時切換 isActive 狀態。當過渡效果完成並且屬性名稱包含 flex 時,該函數會切換面板的 isActive 狀態,觸發文字的上下滑動效果。
const toggleActive = (index, event) => {
if (event.propertyName.includes("flex")) {
panels[index].isActive = !panels[index].isActive;
}
};
在模板中,我使用 v-for 迴圈來渲染每個面板,並透過 @click 事件來綁定 toggleOpen 函數,透過 @transitionend 事件來監聽過渡效果的結束,從而調用 toggleActive 函數。
<div class="panels">
<div
v-for="(panel, index) in panels"
:key="index"
:class="['panel', panel.class, { open: panel.isOpen, 'open-active': panel.isActive }]"
@click="toggleOpen(index)"
@transitionend="toggleActive(index, $event)"
>
<p>{{ panel.text1 }}</p>
<p>{{ panel.text2 }}</p>
<p>{{ panel.text3 }}</p>
</div>
</div>
這段程式碼使用了 Vue 3 的 Composition API,包括 setup 函數、reactive、以及方法的定義,來實現面板的展開與動畫效果。toggleOpen 和 toggleActive 函數負責處理面板的展開和過渡動畫的切換。透過 Composition API 的靈活性,可以更方便地管理響應式狀態和事件處理邏輯。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Scoped CSS Variables and Vue</title>
<style>
:root {
--base: #ffc600;
--spacing: 10px;
--blur: 10px;
}
img {
padding: var(--spacing);
background: var(--base);
filter: blur(var(--blur));
}
.hl {
color: var(--base);
}
body {
text-align: center;
background: #193549;
color: white;
font-family: "helvetica neue", sans-serif;
font-weight: 100;
font-size: 50px;
}
.controls {
margin-bottom: 50px;
}
input {
width: 100px;
}
</style>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body id="app">
<h2>Update CSS Variables with <span class="hl">Vue</span></h2>
<div class="controls">
<label for="spacing">Spacing:</label>
<input
id="spacing"
type="range"
name="spacing"
min="10"
max="200"
value="10"
data-sizing="px"
v-model="spacing"
/>
<label for="blur">Blur:</label>
<input id="blur" type="range" name="blur" min="0" max="25" value="10" data-sizing="px" v-model="blur" />
<label for="base">Base Color</label>
<input id="base" type="color" name="base" value="#ffc600" v-model="base" />
</div>
<img
src="https://images.unsplash.com/photo-1531040630173-7cfb894c8eaa?q=80&w=2804&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
style="width: 800px; width: 500px"
/>
</body>
</html>
<script>
const { ref, watchEffect, createApp } = Vue;
const app = {
setup() {
const spacing = ref(10);
const blur = ref(10);
const base = ref("#ffc600");
watchEffect(() => {
document.documentElement.style.setProperty("--spacing", `${spacing.value}px`);
document.documentElement.style.setProperty("--blur", `${blur.value}px`);
document.documentElement.style.setProperty("--base", base.value);
});
return {
spacing,
blur,
base,
};
},
};
createApp(app).mount("#app");
</script>