該範例使用 Vue 3 的 Composition API 來管理狀態和行為,並且利用了 Vue 的響應式數據和生命週期鉤子來處理鍵盤事件和動畫過渡效果。
以下是完整的 HTML 和 JavaScript 程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Vue Drum Kit</title>
<link rel="stylesheet" href="style.css" />
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body id="app">
<div class="keys">
<div
v-for="key in keys"
:key="key.code"
:data-key="key.code"
:class="['key', { playing: activeKeys.includes(key.label) }]"
@transitionend="removeTransition"
>
<kbd>{{ key.label }}</kbd>
<span class="sound">{{ key.sound }}</span>
</div>
</div>
</body>
</html>
<script>
const { createApp, ref, onMounted, onBeforeUnmount } = Vue;
createApp({
setup() {
const keys = ref([
{ label: "A", sound: "clap" },
{ label: "S", sound: "hihat" },
{ label: "D", sound: "kick" },
{ label: "F", sound: "openhat" },
{ label: "G", sound: "boom" },
{ label: "H", sound: "ride" },
{ label: "J", sound: "snare" },
{ label: "K", sound: "tom" },
{ label: "L", sound: "tink" },
]);
const activeKeys = ref([]);
const playSound = (e) => {
const letter = String.fromCharCode(e.keyCode).toUpperCase(); // 转换为大写字母
const key = keys.value.find((k) => k.label === letter);
if (!key) return;
const audio = new Audio(`sounds/${key.sound}.wav`);
activeKeys.value.push(key.label);
audio.currentTime = 0;
audio.play();
setTimeout(() => {
activeKeys.value = activeKeys.value.filter((l) => l !== key.label);
console.log(activeKeys.value);
}, 100);
};
const removeTransition = (e) => {
if (e.propertyName !== "transform") return;
activeKeys.value = activeKeys.value.filter((label) => label !== e.target.dataset.key);
};
onMounted(() => {
window.addEventListener("keydown", playSound);
});
onBeforeUnmount(() => {
window.removeEventListener("keydown", playSound);
});
return {
keys,
activeKeys,
playSound,
removeTransition,
};
},
}).mount("#app");
</script>
String.fromCharCode
將 ascii 轉成英文字母
const playSound = (e) => {
const key = keys.value.find((k) => k.code === e.keyCode);
if (!key) return;
const audio = new Audio(`sounds/${key.sound}.wav`);
activeKeys.value.push(key.code);
audio.currentTime = 0;
audio.play();
setTimeout(() => {
activeKeys.value = activeKeys.value.filter((code) => code !== key.code);
}, 100);
};
onMounted
的生命週期註冊上述的事件。vue for
迴圈顯示 object<div
v-for="key in keys"
:key="key.code"
:data-key="key.code"
:class="['key', { playing: activeKeys.includes(key.label) }]"
@transitionend="removeTransition"
>
<kbd>{{ key.label }}</kbd>
<span class="sound">{{ key.sound }}</span>
</div>
Display:
html{ background:url(http://...) background-size:cover }