iT邦幫忙

2024 iThome 鐵人賽

DAY 5
0
自我挑戰組

使用 Vue 3 做出 30 個 Side Project系列 第 5

05 - Flex Panel Gallery

  • 分享至 

  • xImage
  •  

摘要

本教學打造出了一個互動式的“彈性面板”界面,使用了 Vue 3 Composition API 和 CSS 的 flexbox 布局和過渡動畫。主要功能如下

內容

該範例 使用 Vue 3 的 Composition API 來實現面板的展開與動畫效果。

1. 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,
    };
}

2. reactive

reactive 用於創建響應式資料。這裡我使用 reactive 來定義 panels,它是一個包含面板資訊的陣列,每個面板都有對應的 CSS 類別、文本內容,以及控制展開和動畫的狀態變量 isOpen 和 isActive。

const panels = reactive([
    {
        class: "panel1",
        text1: "Hey",
        text2: "Let's",
        text3: "Dance",
        isOpen: false,
        isActive: false,
    },
    // 其他面板
]);

3. toggleOpen 函數

toggleOpen 函數用來切換面板的展開狀態。當使用者點擊某個面板時,對應的面板的 isOpen 屬性會在 true 和 false 之間切換,從而觸發 CSS 過渡效果,改變面板的大小和顯示更多文字。

const toggleOpen = (index) => {
    panels[index].isOpen = !panels[index].isOpen;
};

4. toggleActive 函數

toggleActive 函數用來在 CSS 過渡結束時切換 isActive 狀態。當過渡效果完成並且屬性名稱包含 flex 時,該函數會切換面板的 isActive 狀態,觸發文字的上下滑動效果。

const toggleActive = (index, event) => {
    if (event.propertyName.includes("flex")) {
        panels[index].isActive = !panels[index].isActive;
    }
};

5. 使用 v-for 迴圈渲染面板

在模板中,我使用 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>

結果

  1. Demo
  2. Github

上一篇
04 Array Cardio use lodash
下一篇
06 - Type Ahead
系列文
使用 Vue 3 做出 30 個 Side Project7
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言