219 lines
9.7 KiB
Vue
219 lines
9.7 KiB
Vue
<template>
|
|
<div style="height: fit-content; width: fit-content; position: relative;" ref="container">
|
|
<svg class="VPImage image-src" viewBox="0 0 612 612" fill="none" xmlns="http://www.w3.org/2000/svg" ref="svgElement">
|
|
<defs>
|
|
<linearGradient id="gradient_1" gradientUnits="userSpaceOnUse" x1="300" y1="0" x2="300" y2="600">
|
|
<stop offset="0" stop-color="#A1A7F6" />
|
|
<stop offset="1" stop-color="#FFFFFF" stop-opacity="0.2" />
|
|
</linearGradient>
|
|
<linearGradient id="gradient_2" gradientUnits="userSpaceOnUse" x1="110.5" y1="0" x2="110.5" y2="221">
|
|
<stop offset="0.468" stop-color="#BFBAF6" />
|
|
<stop offset="1" stop-color="#FFFFFF" />
|
|
</linearGradient>
|
|
<filter color-interpolation-filters="sRGB" x="-219" y="-219" width="221" height="221" id="filter_3">
|
|
<feFlood flood-opacity="0" result="BackgroundImageFix_1" />
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" in="SourceAlpha" />
|
|
<feOffset dx="0" dy="4" />
|
|
<feGaussianBlur stdDeviation="2" />
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.251 0" />
|
|
<feBlend mode="normal" in2="BackgroundImageFix_1" result="Shadow_2" />
|
|
<feBlend mode="normal" in="SourceGraphic" in2="Shadow_2" result="Shape_3" />
|
|
</filter>
|
|
<linearGradient id="gradient_4" gradientUnits="userSpaceOnUse" x1="55.5" y1="0" x2="55.5" y2="111">
|
|
<stop offset="0" stop-color="#FFFFFF" />
|
|
<stop offset="1" stop-color="#A8A7F3" />
|
|
</linearGradient>
|
|
<filter color-interpolation-filters="sRGB" x="-109" y="-109" width="111" height="111" id="filter_5">
|
|
<feFlood flood-opacity="0" result="BackgroundImageFix_1" />
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" in="SourceAlpha" />
|
|
<feOffset dx="0" dy="4" />
|
|
<feGaussianBlur stdDeviation="2" />
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.251 0" />
|
|
<feBlend mode="normal" in2="BackgroundImageFix_1" result="Shadow_2" />
|
|
<feBlend mode="normal" in="SourceGraphic" in2="Shadow_2" result="Shape_3" />
|
|
</filter>
|
|
<linearGradient id="gradient_6" gradientUnits="userSpaceOnUse" x1="174" y1="0" x2="174" y2="348">
|
|
<stop offset="0.182" stop-color="#A594F6" />
|
|
<stop offset="1" stop-color="#F4E5FF" />
|
|
</linearGradient>
|
|
<filter color-interpolation-filters="sRGB" x="-346" y="-346" width="348" height="348" id="filter_7">
|
|
<feFlood flood-opacity="0" result="BackgroundImageFix_1" />
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" in="SourceAlpha" />
|
|
<feOffset dx="0" dy="4" />
|
|
<feGaussianBlur stdDeviation="2" />
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.251 0" />
|
|
<feBlend mode="normal" in2="BackgroundImageFix_1" result="Shadow_2" />
|
|
<feBlend mode="normal" in="SourceGraphic" in2="Shadow_2" result="Shape_3" />
|
|
</filter>
|
|
<linearGradient id="gradient_8" gradientUnits="userSpaceOnUse" x1="57" y1="0" x2="57" y2="114">
|
|
<stop offset="0" stop-color="#FFFFFF" />
|
|
<stop offset="0.614" stop-color="#C7BAF8" />
|
|
</linearGradient>
|
|
<filter color-interpolation-filters="sRGB" x="-112" y="-112" width="114" height="114" id="filter_9">
|
|
<feFlood flood-opacity="0" result="BackgroundImageFix_1" />
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" in="SourceAlpha" />
|
|
<feOffset dx="0" dy="4" />
|
|
<feGaussianBlur stdDeviation="2" />
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.251 0" />
|
|
<feBlend mode="normal" in2="BackgroundImageFix_1" result="Shadow_2" />
|
|
<feBlend mode="normal" in="SourceGraphic" in2="Shadow_2" result="Shape_3" />
|
|
</filter>
|
|
</defs>
|
|
<g transform="translate(6 2)">
|
|
<g>
|
|
<path
|
|
d="M300 0C465.708 0 600 134.292 600 300C600 300 600 300 600 300C600 465.708 465.708 600 300 600C300 600 300 600 300 600C134.292 600 0 465.708 0 300C0 300 0 300 0 300C0 134.292 134.292 0 300 0Z"
|
|
fill="#5A00FF" fill-rule="evenodd" />
|
|
<path
|
|
d="M300 0C465.708 0 600 134.292 600 300C600 300 600 300 600 300C600 465.708 465.708 600 300 600C300 600 300 600 300 600C134.292 600 0 465.708 0 300C0 300 0 300 0 300C0 134.292 134.292 0 300 0Z"
|
|
fill="url(#gradient_1)" fill-rule="evenodd" />
|
|
</g>
|
|
<path
|
|
d="M0 110.5C0 49.4725 49.4725 0 110.5 0C171.527 0 221 49.4725 221 110.5C221 171.527 171.527 221 110.5 221C49.4725 221 0 171.527 0 110.5Z"
|
|
fill="url(#gradient_2)" fill-rule="evenodd" filter="url(#filter_3)"
|
|
transform="translate(293 324)" />
|
|
<path
|
|
d="M0 55.5C0 24.8482 24.8482 0 55.5 0C86.1518 0 111 24.8482 111 55.5C111 86.1518 86.1518 111 55.5 111C24.8482 111 0 86.1518 0 55.5Z"
|
|
fill="url(#gradient_4)" fill-rule="evenodd" filter="url(#filter_5)" transform="translate(48 269)" />
|
|
<path
|
|
d="M0 174C0 77.9024 77.9024 0 174 0C270.098 0 348 77.9024 348 174C348 270.098 270.098 348 174 348C77.9024 348 0 270.098 0 174Z"
|
|
fill="url(#gradient_6)" fill-rule="evenodd" filter="url(#filter_7)" transform="translate(188 56)" />
|
|
<path
|
|
d="M0 57C0 25.5198 25.5198 0 57 0C88.4802 0 114 25.5198 114 57C114 88.4802 88.4802 114 57 114C25.5198 114 0 88.4802 0 57Z"
|
|
fill="url(#gradient_8)" fill-rule="evenodd" filter="url(#filter_9)"
|
|
transform="translate(388 129)" />
|
|
</g>
|
|
</svg>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { onMounted, ref } from 'vue'
|
|
import { gsap } from 'gsap'
|
|
|
|
const container = ref(null)
|
|
const svgElement = ref(null)
|
|
|
|
onMounted(() => {
|
|
const paths = svgElement.value.querySelectorAll('path')
|
|
|
|
// 设置初始状态
|
|
gsap.set(paths, {
|
|
strokeDasharray: (i, target) => {
|
|
const length = target.getTotalLength()
|
|
target.style.strokeDasharray = length
|
|
return length
|
|
},
|
|
strokeDashoffset: (i, target) => target.getTotalLength(),
|
|
stroke: 'var(--vp-c-brand-2)',
|
|
strokeWidth: 3,
|
|
fillOpacity: 0
|
|
})
|
|
|
|
// 创建主时间线
|
|
const master = gsap.timeline()
|
|
|
|
// 描边动画时间线
|
|
const drawTimeline = gsap.timeline({
|
|
defaults: { duration: 1.5, ease: "power2.inOut" }
|
|
})
|
|
|
|
// 为所有路径添加描边动画
|
|
paths.forEach(path => {
|
|
drawTimeline.to(path, {
|
|
strokeDashoffset: 0,
|
|
}, "<+=0.3")
|
|
})
|
|
|
|
// 反向描边消失动画时间线
|
|
const reverseTimeline = gsap.timeline({
|
|
defaults: { duration: 1.5, ease: "power2.inOut" }
|
|
})
|
|
|
|
// 为所有路径添加反向描边动画
|
|
paths.forEach(path => {
|
|
reverseTimeline.to(path, {
|
|
fillOpacity: 1,
|
|
strokeDashoffset: (i, target) => target.getTotalLength()
|
|
}, "<")
|
|
})
|
|
|
|
// 微扰动画时间线
|
|
const wiggleTimeline = gsap.timeline({
|
|
repeat: -1,
|
|
yoyo: true,
|
|
defaults: {
|
|
duration: 2,
|
|
ease: "sine.inOut"
|
|
}
|
|
})
|
|
|
|
// 为每个圆形元素创建不同的微扰动画
|
|
const wiggleElements = [
|
|
{
|
|
el: svgElement.value.querySelector('[transform="translate(293 324)"]'),
|
|
x: "+=12", y: "+=5", rotation: "+=2"
|
|
},
|
|
{
|
|
el: svgElement.value.querySelector('[transform="translate(48 269)"]'),
|
|
x: "-=5", y: "-=10", rotation: "-=1"
|
|
},
|
|
{
|
|
el: svgElement.value.querySelector('[transform="translate(188 56)"]'),
|
|
x: "-=4", y: "+=5", rotation: "+=3"
|
|
},
|
|
{
|
|
el: svgElement.value.querySelector('[transform="translate(388 129)"]'),
|
|
x: "+=9", y: "+=4", rotation: "-=2"
|
|
}
|
|
]
|
|
|
|
// 为每个元素添加独特的微扰动画
|
|
wiggleElements.forEach(item => {
|
|
wiggleTimeline.to(item.el, {
|
|
x: item.x,
|
|
y: item.y,
|
|
rotation: item.rotation,
|
|
scale: item.scale,
|
|
transformOrigin: "center center"
|
|
}, "<")
|
|
})
|
|
|
|
// 控制动画顺序
|
|
master.add(drawTimeline)
|
|
.add(reverseTimeline, "+=0.5")
|
|
.add(wiggleTimeline) // 所有动画完成后开始微扰动画
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.VPHero .VPImage {
|
|
filter: drop-shadow(-2px 4px 6px rgba(0, 0, 0, .2));
|
|
}
|
|
|
|
.image-src {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 320px;
|
|
height: 320px;
|
|
object-fit: contain;
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
.circle-animation {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 320px;
|
|
height: 320px;
|
|
transform: translate(-50%, -50%);
|
|
color: var(--vp-c-brand-1);
|
|
}
|
|
|
|
.circle-animation circle {
|
|
stroke-width: 3;
|
|
stroke-linecap: round;
|
|
}
|
|
</style>
|