嘿!你有沒有注意過那些可愛的按鈕或圖標,在網頁上輕輕一碰就會旋轉起來,簡單卻讓人忍不住再多點幾次?
其實這就是網頁設計中的旋轉動效,不僅能讓頁面看起來更有趣,還能帶給使用者一種「哇,這個網站好好玩」的感覺!
今天,我們要來聊聊這個超受歡迎的網頁動態特效——rotation(旋轉效果)
不過,光是讓一個元素轉起來怎麼夠呢?
我們還會從基礎講起,然後一步步進階,教你怎麼把這些旋轉效果玩得更有創意、更有趣!
甚至,我們會用 Vue.js 來做一個簡單又讓人上癮的小遊戲,讓畫面動起來,讓人眼睛離不開!
我們先來看看怎麼實現最基本的左旋轉和右旋轉特效,接著再進一步探討如何把它變成一個好玩的小遊戲。
準備好了嗎?Let's go~ 🎮
接下來,我們來看看如何用 Vue.js 實現一個簡單又有趣的旋轉動效!
這裡我們會創建一個 8x8 的方格,展示兩種旋轉特效:順時針旋轉和逆時針旋轉。
畫面上的元素會是一個個可愛的壽司 🍣 和旋轉 icon ↻,是不是有點餓了呢?
嘿嘿,別急,先讓它們轉起來,看看旋轉特效是怎麼讓這些小圖案更活潑有趣的吧!
<script lang="ts" setup>
import { computed } from "vue";
// 定義方格的行列數(8x8)
const pixelNum: number = 8;
// 定義一個包含旋轉圖案的字符列表
const characterList: string[] = ["🍣", "↻"]; // 我們用壽司和旋轉符號來展示旋轉效果
// sushiGrid 是一個計算屬性,用來生成 8x8 的網格,每個元素有自己的字符和旋轉方向
const sushiGrid = computed(() => {
return Array.from({ length: pixelNum * pixelNum }, (_, index) => {
// 計算當前元素的行和列
const row = Math.floor(index / pixelNum);
const column = index % pixelNum;
// 根據行列的和決定字符(壽司或旋轉符號)
const character = characterList[(row + column) % 2];
// 根據行列的和來決定旋轉方向,行列和為偶數時設置為 reverse(逆時針旋轉),否則為順時針旋轉
const rotationDirection = (row + column) % 2 === 0 ? "reverse" : "";
// 返回一個包含字符和旋轉方向的物件
return { character, rotationDirection };
});
});
</script>
pixelNum
:這裡我們定義了一個數字 8,表示網格是 8 行 8 列的方格,總共有 64 個元素。characterList
:我們使用了兩個字符——一個是壽司符號 🍣,另一個是旋轉符號 ↻。這兩個符號將會被交替放置在方格中。sushiGrid
:這是一個 Vue.js 的 computed
(計算屬性),用來動態生成一個 8x8 的方格。
Array.from()
,我們創建一個長度為 pixelNum * pixelNum
的陣列(這裡是 64 個元素)。"reverse"
,代表逆時針旋轉。否則為順時針旋轉。<template>
<div id="sushiContainer">
<!-- 這裡用 v-for 迴圈遍歷 sushiGrid 中的每個元素 -->
<div v-for="(item, index) in sushiGrid" :key="index"
:class="`${item.rotationDirection} flex justify-center items-center origin-center`">
{{ item.character }}
</div>
</div>
</template>
v-for
:我們使用 Vue 的 v-for
指令來遍歷 sushiGrid
中的每個元素,並且根據 index
來為每個元素分配一個唯一的 key
。item.rotationDirection
:這裡根據每個元素的 rotationDirection
動態添加 reverse
或空字串作為 class
,決定元素是順時針還是逆時針旋轉。item.character
:每個格子中的字符是壽司 🍣 或旋轉符號 ↻,這取決於我們之前在 computed
中設定的行列規則。class
屬性:使用 Flexbox 將每個格子中的字符置中,並且設置旋轉的中心點為該元素的中心。<style scoped>
#sushiContainer {
--pixel-num: 8;
display: grid;
font-size: calc(100vw / var(--pixel-num)); /* 每個格子的大小會根據視窗寬度自動縮放 */
--pixel-height: calc(100vw / var(--pixel-num)); /* 計算每個格子的高度 */
grid-template:
repeat(var(--pixel-num), var(--pixel-height)) /
repeat(var(--pixel-num), var(--pixel-height)); /* 創建 8x8 方格佈局 */
}
#sushiContainer>* {
animation: rotation 3s linear infinite; /* 為每個格子添加旋轉動畫,循環3秒 */
}
#sushiContainer .reverse {
animation-direction: reverse; /* 當有 reverse class 時,元素逆時針旋轉 */
}
/* 定義旋轉動畫 */
@keyframes rotation {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg); /* 順時針旋轉一圈 */
}
}
</style>
#sushiContainer
:這裡我們使用 CSS Grid 來創建一個 8x8 的方格佈局,並且根據螢幕的寬度自動調整格子的大小。animation
:每個元素都應用了一個叫做 rotation
的 CSS 動畫,持續時間為 3 秒,並且會無限循環。animation-direction: reverse
:如果元素有 reverse
類名,它會以逆時針的方式旋轉。@keyframes rotation
:這是關鍵的旋轉動畫,從 0 度旋轉到 360 度,讓元素順時針旋轉。在這個範例中,我們成功用 Vue.js 和簡單的 CSS 實現了旋轉動效,讓壽司 🍣 和旋轉 icon ↻ 都活靈活現地轉了起來!
我們透過 左旋轉 和 右旋轉 的搭配,讓每個格子都充滿動感,並巧妙地使用了 @keyframes
和 animation-direction
來輕鬆控制旋轉方向。
這些基礎打好之後,接下來就能進階挑戰,讓這些旋轉特效變成有趣的互動遊戲了!
準備好進一步深入探索了嗎?Let’s roll~ 🎮
我們從簡單的旋轉特效延伸到一個有趣的互動遊戲。
遊戲的核心目標是找出並點擊畫面中隨機出現的目標食物字符,並消除它們。
如果玩家成功找出所有目標字符,遊戲將顯示「恭喜過關」的彈窗,並提供「再玩一次」的選項。
這段代碼展示了從簡單的旋轉特效延伸到一個有趣的互動遊戲。
遊戲的核心目標是找出並點擊畫面中隨機出現的目標食物字符,並消除它們。如果玩家成功找出所有目標字符,遊戲將顯示「恭喜過關」的彈窗,並提供「再玩一次」的選項。
foodList
中隨機挑選一組字符,並將這些字符作為遊戲中的旋轉圖案。const foodList = ['🍕', '🍔', '🍟', '🌭', '🍿', '🧂', '🥓', '🥚', '🥞', '🍳', '🍞', '🥐', '🥨', '🥯', '🥖', '🧀', '🥗', '🥙', '🥪', '🌮', '🌯', '🥫', '🍖', '🍗', '🥩', '🍠', '🥟', '🥠', '🥡', '🍱', '🍘', '🍙', '🍚', '🍛', '🍜', '🍣', '🍤', '🍥', '🥮', '🍢', '🥘', '🍲', '🍝', '🥣', '🥧', '🍦', '🍧', '🍨', '🍩', '🍪', '🎂', '🍰', '🧁', '🍫', '🍬', '🍭', '🍡', '🍮', '🍯', '🍼', '🥛', '☕', '🍵', '🍶', '🍾', '🍷', '🍸', '🍹', '🍺', '🍻', '🥂', '🥃', '🥤', '🥢', '🍴', '🥄', '🏺', '🥝', '🥥', '🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🥭', '🍎', '🍏', '🍐', '🍑', '🍒', '🍓', '🍅', '🍆', '🌽', '🌶', '🍄', '🥑', '🥒', '🥬', '🥦', '🥔', '🥕', '🌰', '🥜', '💐', '🌸', '🌹', '🌺', '🌻', '🌼', '🌷', '🥀', '🌱', '🌲', '🌳', '🌴', '🌵', '🌾', '🌿', '🍀', '🍁', '🍂', '🍃'];
const pixelNum = 8;
const getRandomElements = function <T>(arr: T[], min: number, max: number): T[] {
const count = Math.floor(Math.random() * (max - min + 1)) + min;
const shuffled = [...arr].sort(() => 0.5 - Math.random());
return shuffled.slice(0, count);
}
const characterList = getRandomElements(foodList, 3, 16);
const targetCharacter = ref<string>(getRandomCharacter());
foodList
中隨機挑選 3 到 16 個字符作為遊戲中的圖案,並從中選擇一個目標字符,讓玩家去找出來。const handleClick = (index: number) => {
const currentCharacter = sushiGrid.value[index];
if (currentCharacter.character === targetCharacter.value) {
sushiGrid.value[index] = { ...currentCharacter, character: "⭕" };
if (isLevelComplete.value) {
modelTitle.value = "恭喜過關";
modelContent.value = `您真厲害!已經找到所有 ${targetCharacter.value} 了!`;
buttonLabel.value = "再玩一次";
isModalVisible.value = true;
}
return;
}
sushiGrid.value[index] = { ...currentCharacter, character: "❌" };
setTimeout(() => {
sushiGrid.value[index] = currentCharacter;
}, 1000);
};
const startGame = () => {
sushiGrid.value = Array.from({ length: pixelNum * pixelNum }, () => ({
character: getRandomCharacter(),
rotationDirection: Math.random() > 0.5 ? 'reverse' : ''
}));
targetCharacter.value = getRandomCharacter();
buttonLabel.value = "開始遊戲";
modelTitle.value = "遊戲規則";
modelContent.value = `目標:找到並消除所有 ${targetCharacter.value}`;
isModalVisible.value = true;
isGameStart.value = false;
};
<!-- Modal Component -->
<div v-if="isModalVisible" class="fixed inset-0 bg-black bg-opacity-60 flex justify-center items-center z-1 font-mono">
<div class="w-1/2 h-1/3 bg-white p-8 rounded-lg max-w-md text-center shadow-lg animate-fade-in scale-95">
<h2 class="text-4xl mb-6">{{ modelTitle }}</h2>
<p class="text-2xl mb-10">{{ modelContent }}</p>
<button @click="closeModal" class="bg-orange-500 text-white text-xl font-bold py-2 px-6 rounded-lg hover:bg-orange-700">
{{ buttonLabel }}
</button>
</div>
</div>
這樣一個充滿旋轉與趣味的小遊戲,不僅讓我們體驗到 Vue.js 動效的魔力,更感受到編程帶來的創造力與成就感!
其實,寫程式就像這些旋轉的壽司食物一樣,每一行代碼都是一次新的嘗試,每一次挑戰都是讓我們變得更好的機會。
希望你玩得開心,學得愉快,未來的每個小專案都能像這次一樣充滿樂趣!
Keep coding,讓你的世界旋轉起來吧!🎉