CodePen Link: https://codepen.io/zyrxdkoz/pen/yLXgxOp
效果說明
滑鼠移到button點擊,會出現水波紋的效果。
CSS
// 基本樣式
button {
background-color: purple;
color: #fff;
border: 1px purple solid;
border-radius: 30px;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 2px;
padding: 20px 30px;
overflow: hidden;
margin: 10px 0;
position: relative;
}
button:focus {
outline: none;
}
// 預先寫好circle選擇器的樣式,準備讓javascript來生成
button .circle {
position: absolute;
background-color: #fff;
width: 100px;
height: 100px;
border-radius: 50%;
transform: translate(-50%, -50%) scale(0);
animation: scale 0.5s ease-out;
}
// 動態效果設定
@keyframes scale {
to {
transform: translate(-50%, -50%) scale(3);
opacity: 0;
}
}
javascript
const buttons = document.querySelectorAll('.ripple')
buttons.forEach(button => {
button.addEventListener('click', function (e) {
// 選定滑鼠在視窗上的位置
const x = e.clientX
const y = e.clientY
// 選定按鈕的頂部和側邊的位置
const buttonTop = e.target.offsetTop
const buttonLeft = e.target.offsetLeft
// 根據出滑鼠點擊的地方和按鈕頂部、側邊,來判斷滑鼠到邊緣的距離。
const xInside = x - buttonLeft
const yInside = y - buttonTop
// 建立一個<span>,然後加入circle選擇器做渲染
const circle = document.createElement('span')
circle.classList.add('circle')
// 依照前面計算出來的兩個點,使渲染的circle擴展到邊緣
circle.style.top = yInside + 'px'
circle.style.left = xInside + 'px'
// 將建立好的DOM element放到button當中
this.appendChild(circle)
// 效果維持0.5秒就讓它消失
setTimeout(() => circle.remove(), 500)
})
})
in SectionQA.vue
// src/views/SectionQA.vue
<template>
<home-btn />
<div
class="
faq-container
w-full
h-[vh100]
bg-gray-100
p-5
flex flex-col
justify-start
items-center
"
>
<h1
class="
text-md text-gray-900
font-extrabold
mt-10
mb-10
md:text-2xl
lg:text-3xl
"
>
Frequently Asked Questions
</h1>
// 用v-for迴圈渲染模板,然後每個渲染出來的QA都會綁定qa.id和toggleAcitve
<div v-for="qa in qaArray" :key="qa.id" @click="toggleActive(qa.id)">
<div
class="
faq
w-[50vw]
relative
overflow-hidden
bg-transparent
border-2 border-gray-500
rounded-xl
mb-8
p-7
duration-150
ease-in-out
"
// 若qa.isActive為true,則帶入active選擇器
:class="{ active: qa.isActive }"
>
<h3 class="faq-title font-semibold mr-[50px]">
{{ qa.question }}
</h3>
<p class="faq-answer text-red-800 mt-5">{{ qa.answer }}</p>
<button
class="
faq-toggle
flex
group
justify-center
items-center
absolute
p-0
top-3
right-3
rounded-full
h-[30px]
w-[30px]
border-gray-500
"
>
<Icon
icon="bx:bxs-chevron-down"
class="icon-arrow-down text-gray-800 pointer-events-none"
height="36"
/>
<Icon
icon="pepicons:times"
class="icon-times text-[#111] pointer-events-none"
height="28"
/>
</button>
</div>
</div>
</div>
</template>
<script>
import { Icon } from '@iconify/vue'
import HomeBtn from '../components/HomeBtn.vue'
import { ref } from 'vue'
export default {
components: { HomeBtn, Icon },
setup() {
// 建立好資料,然後運用v-for迴圈來渲染到模板上
const data = [
{
question: "Why shouldn't we trust atoms?",
answer: 'They make up everything',
isActive: true,
id: 1,
},
{
question: 'What do you call someone with no body and no nose?',
answer: 'Nobody Knows',
isActive: false,
id: 2,
},
{
question: "What's the object-oriented way to become wealthy?",
answer: 'Inheritance',
isActive: false,
id: 3,
},
{
question: 'How many tickles does it take to tickle an octopus?',
answer: 'Ten-tickles!',
isActive: false,
id: 4,
},
{
question: 'What is: 1 + 1?',
answer: 'Depends on who are you asking.',
isActive: false,
id: 5,
},
]
const qaArray = ref(data)
// 當QA被點擊的時候,會帶入id比對,然後改變或維持isActive的值。
const toggleActive = (id) => {
qaArray.value.forEach(function (qa) {
if (id === qa.id) {
qa.isActive = !qa.isActive
} else {
qa.isActive
}
})
}
// 將被ref函式包裝進去的陣列,以及toggleActive函式渲染到模板中
return {
qaArray,
toggleActive,
}
},
}
</script>
// css部分主要是彌補tailwind css達成的效果。
<style lang="scss" scoped>
.faq {
transition: 0.3s ease;
&.active {
background-color: white;
.faq-answer {
display: block;
}
.faq-toggle {
background-color: #9fa4a8;
.icon-arrow-down {
display: none;
}
.icon-times {
display: block;
color: white;
}
&:focus {
outline: none;
}
}
}
.faq-title {
margin: 0 35px 0 0;
}
.faq-answer {
display: none;
}
.icon-times {
display: none;
}
}
</style>
實作過程的心得