add some animation

This commit is contained in:
锦恢 2025-06-05 03:37:21 +08:00 committed by li1553770945
parent 0ac6003c19
commit e64a1b5419
10 changed files with 382 additions and 85 deletions

View File

@ -1,9 +1,8 @@
<template>
<DefaultTheme.Layout id="k-layout">
</DefaultTheme.Layout>
<ScrollBar />
</template>
<script setup lang="ts">
@ -12,6 +11,13 @@ import DefaultTheme from 'vitepress/theme';
import { nextTick, onMounted, provide } from 'vue';
import mediumZoom from "medium-zoom";
import { animateIn, animateOut } from './hook/animate';
import ScrollBar from './components/scrollbar/index.vue';
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
//
gsap.registerPlugin(ScrollTrigger);
const data = useData()
const router = useRouter()
@ -21,6 +27,7 @@ const enableTransitions = () =>
const isDark = data.isDark;
const setupMediumZoom = () => {
mediumZoom("[data-zoomable]", {
background: "transparent",
@ -65,14 +72,78 @@ const handleRouteChangeStart = async (to: string) => {
const handleRouteChangeComplete = async (to: string) => {
await animateOut();
setupMediumZoom();
makeHomeAnimation();
};
router.onBeforeRouteChange = handleRouteChangeStart;
router.onAfterRouteChange = handleRouteChangeComplete;
function makeHomeAnimation() {
if (router.route.path !== '/openmcp/') {
return;
}
gsap.from(".main", {
opacity: 0, //
x: -100, // 100px
duration: 1.2, //
ease: "power2.out", //
});
gsap.from(".VPHero .VPImage", {
opacity: 0, //
x: 100, // 100px
duration: 1.2, //
ease: "power2.out", //
});
gsap.from(".VPFeatures.VPHomeFeatures", {
opacity: 0, //
y: 100, // 100px
duration: 1.2, //
ease: "power2.out", //
});
const elements = [
{ selector: ".bilibili-player-container", start: "top 65%", end: "top 65%" },
{ selector: "#openmcp-为谁准备", trigger: '#openmcp-为谁准备', start: "top 65%", end: "top 65%" },
{ selector: ".k-tabs", trigger: '#openmcp-为谁准备', start: "top 65%", end: "top 65%" },
{ selector: "#问题解答-faq", trigger: '#问题解答-faq', start: "top 65%", end: "top 65%" },
{ selector: ".el-collapse", trigger: '#问题解答-faq', start: "top 65%", end: "top 65%" },
];
elements.forEach(element => {
gsap.fromTo(element.selector,
{
opacity: 0,
y: 100,
duration: 1.2,
ease: "power2.out",
},
{
opacity: 1,
y: 0,
duration: 1.2, //
ease: "power2.out", //
scrollTrigger: {
trigger: element.trigger || element.selector,
start: "top 70%",
end: "top 70%",
scrub: false,
toggleActions: "play none reverse none",
}
}
);
});
}
onMounted(() => {
setupMediumZoom();
makeHomeAnimation();
});
</script>
@ -82,6 +153,13 @@ onMounted(() => {
transition: background-color 0.15s ease, color 0.3s ease;
}
html::-webkit-scrollbar,
body::-webkit-scrollbar {
width: 0px;
}
.medium-zoom-overlay {
backdrop-filter: blur(5rem);
}
@ -109,5 +187,4 @@ onMounted(() => {
transform: translateY(100px);
opacity: 0;
}
</style>

View File

@ -78,6 +78,7 @@ const tabsContainer: TabsContainer = reactive({
const container = tabsContainer.panelContainer;
const panels = Array.from(container.children) as HTMLElement[];
//
panels.forEach((panel, index) => {
console.log('index', index);
console.log('id', id);

View File

@ -54,7 +54,7 @@ function playVideo() {
aspect-ratio: 16/9;
border-radius: .5em;
overflow: hidden;
border: 2px solid var(--vp-c-brand-3);
border: 3px solid var(--vp-c-brand-2);
}
.cover-container {
@ -78,7 +78,7 @@ function playVideo() {
width: 64px;
height: 64px;
border-radius: 50%;
background-color: var(--vp-c-brand-3);
background-color: var(--vp-c-brand-2);
border: none;
color: var(--vp-c-bg);
cursor: pointer;

View File

@ -0,0 +1,25 @@
import { reactive } from 'vue';
interface ScrollbarController {
element: any;
display: boolean;
height: number;
width: number;
top: number;
opacity: number;
percentage: number;
}
export const scrollbarController = reactive<ScrollbarController>({
element: undefined,
display: true,
height: 200,
width: 5,
top: 0,
opacity: 0,
percentage: 0
});
export const navigationBarController = reactive({
show: true
});

View File

@ -0,0 +1,113 @@
<template>
<div
class="k-scrollerbar"
:style="scrollbarStyle"
:ref="el => scrollbarController.element = el"
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeave"
>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { scrollbarController } from './controller';
import { navigationBarController } from './controller';
const scrollbarStyle = computed(() => ({
height: scrollbarController.height + 'px',
width: scrollbarController.width + 'px',
opacity: scrollbarController.opacity
}));
let disappearHandler: undefined | number = undefined;
function clearDisappearHandler() {
if (disappearHandler) {
clearTimeout(disappearHandler);
}
}
function hideDisappearHandler(timeout=500) {
disappearHandler = setTimeout(() => {
scrollbarController.opacity = 0;
}, timeout);
}
function onMouseEnter() {
clearDisappearHandler();
scrollbarController.opacity = 1;
scrollbarController.width = 8;
}
function onMouseLeave() {
scrollbarController.width = 5;
hideDisappearHandler(1000);
}
function onScroll(event) {
clearDisappearHandler();
scrollbarController.opacity = 1;
//
const totalHeight = document.documentElement.scrollHeight;
//
const viewportHeight = window.innerHeight;
//
if (viewportHeight >= totalHeight) {
scrollbarController.opacity = 0;
return;
}
// [0, totalHeight - viewportHeight]
const scrollPosition = window.scrollY;
//
const ratio = viewportHeight / totalHeight;
const scrollbarHeight = Math.max(20, viewportHeight * ratio);
// top [0, viewportHeight - scrollbarHeight]
const percentage = scrollPosition / (totalHeight - viewportHeight);
const scrollbarTop = percentage * (viewportHeight);
scrollbarController.height = scrollbarTop;
// scrollbarController.top = scrollbarTop;
scrollbarController.percentage = percentage;
}
function onScrollEnd() {
hideDisappearHandler();
}
function onWheel(event) {
if (event.deltaY > 0) {
navigationBarController.show = false;
} else {
navigationBarController.show = true;
}
}
document.addEventListener('scroll', onScroll);
document.addEventListener('scrollend', onScrollEnd);
document.addEventListener('resize', onScroll);
document.addEventListener('wheel', onWheel);
</script>
<style>
.k-scrollerbar {
left: 0;
top: 0;
background-color: var(--vp-c-brand-2);
border-radius: .3em;
position: fixed;
z-index: 200;
transition-property: width, opacity;
transition-duration: 0.5s;
transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
transition: all 0.35s cubic-bezier(0.23, 1, 0.32, 1);
cursor: pointer;
}
</style>

View File

@ -0,0 +1,52 @@
.tagline {
width: fit-content;
}
.tagline {
position: relative;
display: inline-block;
overflow: hidden;
padding: 0.5rem 0;
cursor: pointer;
}
.tagline:hover::before {
transform: translateX(0);
}
.tagline::before {
content: "";
position: absolute;
left: 0;
bottom: 0;
height: 2px;
width: 100%;
background-color: var(--vp-c-brand-2);
transform: translateX(-105%);
transition: transform 1.2s cubic-bezier(0.23, 1, 0.32, 1);
}
.VPFeatures .item {
cursor: pointer;
transition: .5s cubic-bezier(0.23, 1, 0.32, 1);
}
.VPFeatures .item:hover {
transform: scale(1.05);
}
.VPFeatures .item .box {
transition: .5s cubic-bezier(0.23, 1, 0.32, 1);
border-radius: .5em;
}
.VPFeatures .item:hover .box {
background-color: var(--vp-c-brand-3);
}
.VPFeatures .item:hover .box .details {
color: var(--vp-c-white);
}

View File

@ -44,30 +44,34 @@
* -------------------------------------------------------------------------- */
:root {
--vp-c-default-1: var(--vp-c-gray-1);
--vp-c-default-2: var(--vp-c-gray-2);
--vp-c-default-3: var(--vp-c-gray-3);
--vp-c-default-soft: var(--vp-c-gray-soft);
--vp-c-default-1: var(--vp-c-gray-1);
--vp-c-default-2: var(--vp-c-gray-2);
--vp-c-default-3: var(--vp-c-gray-3);
--vp-c-default-soft: var(--vp-c-gray-soft);
--vp-c-brand-1: #d8a8e7; /* 较深的变体 */
--vp-c-brand-2: #C285D6; /* 基底颜色 */
--vp-c-brand-3: #a368b8; /* 较浅的变体 */
--vp-c-brand-soft: rgba(194, 133, 214, 0.1); /* 半透明的柔和版本 */
--vp-c-brand-1: #d8a8e7;
/* 较深的变体 */
--vp-c-brand-2: #C285D6;
/* 基底颜色 */
--vp-c-brand-3: #a368b8;
/* 较浅的变体 */
--vp-c-brand-soft: rgba(194, 133, 214, 0.1);
/* 半透明的柔和版本 */
--vp-c-tip-1: var(--vp-c-brand-1);
--vp-c-tip-2: var(--vp-c-brand-2);
--vp-c-tip-3: var(--vp-c-brand-3);
--vp-c-tip-soft: var(--vp-c-brand-soft);
--vp-c-tip-1: var(--vp-c-brand-1);
--vp-c-tip-2: var(--vp-c-brand-2);
--vp-c-tip-3: var(--vp-c-brand-3);
--vp-c-tip-soft: var(--vp-c-brand-soft);
--vp-c-warning-1: var(--vp-c-yellow-1);
--vp-c-warning-2: var(--vp-c-yellow-2);
--vp-c-warning-3: var(--vp-c-yellow-3);
--vp-c-warning-soft: var(--vp-c-yellow-soft);
--vp-c-warning-1: var(--vp-c-yellow-1);
--vp-c-warning-2: var(--vp-c-yellow-2);
--vp-c-warning-3: var(--vp-c-yellow-3);
--vp-c-warning-soft: var(--vp-c-yellow-soft);
--vp-c-danger-1: var(--vp-c-red-1);
--vp-c-danger-2: var(--vp-c-red-2);
--vp-c-danger-3: var(--vp-c-red-3);
--vp-c-danger-soft: var(--vp-c-red-soft);
--vp-c-danger-1: var(--vp-c-red-1);
--vp-c-danger-2: var(--vp-c-red-2);
--vp-c-danger-3: var(--vp-c-red-3);
--vp-c-danger-soft: var(--vp-c-red-soft);
}
/**
@ -75,15 +79,15 @@
* -------------------------------------------------------------------------- */
:root {
--vp-button-brand-border: transparent;
--vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-bg: var(--vp-c-brand-3);
--vp-button-brand-hover-border: transparent;
--vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
--vp-button-brand-active-border: transparent;
--vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-c-brand-1);
--vp-button-brand-border: transparent;
--vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-bg: var(--vp-c-brand-3);
--vp-button-brand-hover-border: transparent;
--vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
--vp-button-brand-active-border: transparent;
--vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-c-brand-1);
}
/**
@ -91,27 +95,27 @@
* -------------------------------------------------------------------------- */
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg,
#bd34fe 30%,
#41d1ff);
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg,
#bd34fe 30%,
#41d1ff);
--vp-home-hero-image-background-image: linear-gradient(-45deg,
#bd34fe 50%,
#47caff 50%);
--vp-home-hero-image-filter: blur(44px);
--vp-home-hero-image-background-image: linear-gradient(-45deg,
#bd34fe 50%,
#47caff 50%);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
/**
@ -119,15 +123,15 @@
* -------------------------------------------------------------------------- */
:root {
--vp-custom-block-tip-border: transparent;
--vp-custom-block-tip-text: var(--vp-c-text-1);
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-border: transparent;
--vp-custom-block-tip-text: var(--vp-c-text-1);
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
}
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);
}
:root {
@ -138,34 +142,34 @@
--el-text-color-primary: var(--vp-c-text-1) !important;
--el-border-color: var(--vp-c-border) !important;
--el-bg-color: var(--vp-c-bg) !important;
--el-collapse-border-color: var(--vp-c-border) !important;
--el-collapse-border-color: var(--vp-c-border) !important;
}
.el-collapse {
border-top: 1px solid transparent !important;
border-top: 1px solid transparent !important;
}
.el-collapse-item__header {
border-top: unset !important;
border-top: unset !important;
background-color: var(--vp-c-bg) !important;
border-bottom: 1px solid var(--vp-c-border) !important;
height: fit-content !important;
border-bottom: 1px solid var(--vp-c-border) !important;
height: fit-content !important;
}
.el-collapse-item__title {
font-size: 1.2rem;
padding: 10px 0;
font-size: 1.2rem;
padding: 10px 0;
}
.el-collapse-item__content {
padding: 20px 0 0 0;
font-size: 15px !important;
padding: 20px 0 0 0;
font-size: 15px !important;
}
.el-collapse-item__wrap {
border-bottom: 1px solid var(--vp-c-border) !important;
border-bottom: 1px solid var(--vp-c-border) !important;
}
/**
@ -173,11 +177,11 @@
* -------------------------------------------------------------------------- */
.DocSearch {
--docsearch-primary-color: var(--vp-c-brand-1) !important;
--docsearch-primary-color: var(--vp-c-brand-1) !important;
}
.two-side-layout .image-container {
display: unset !important;
display: unset !important;
}
@ -189,61 +193,78 @@
}
.home-tab {
min-height: 477px;
min-height: 477px;
}
@media (max-width: 500px) {
.home-tab {
min-height: 677px;
min-height: 677px;
}
}
.VPHero .image-container img {
box-shadow: unset !important;
box-shadow: unset !important;
}
iframe {
border: 2px solid var(--vp-c-brand-3);
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: border-color 0.3s ease;
border: 2px solid var(--vp-c-brand-3);
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: border-color 0.3s ease;
}
.VPMenu {
background-color: rgba(255, 255, 255, 0.55) !important;
border: unset !important;
backdrop-filter: blur(10px);
background-color: rgba(255, 255, 255, 0.55) !important;
border: unset !important;
backdrop-filter: blur(10px);
}
.dark .VPMenu {
background-color: rgba(0, 0, 0, 0.55) !important;
backdrop-filter: blur(10px);
background-color: rgba(0, 0, 0, 0.55) !important;
backdrop-filter: blur(10px);
}
.VPTeamPage {
margin-top: 0 !important;
margin-top: 0 !important;
}
/* 自定义全局滚动条样式 */
::-webkit-scrollbar {
width: 8px;
width: 0px;
}
::-webkit-scrollbar-track {
background: var(--vp-c-default-soft);
background: var(--vp-c-default-soft);
}
::-webkit-scrollbar-thumb {
background: var(--vp-c-brand-3);
border-radius: 4px;
background: var(--vp-c-brand-3);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--vp-c-brand-2);
background: var(--vp-c-brand-2);
}
/* 设置选中文本的背景色和文字颜色 */
::selection {
background: var(--vp-c-brand-2);
color: white;
}
/* 兼容 Firefox */
::-moz-selection {
background: var(--vp-c-brand-2);
color: white;
}
.VPHero .name.clip {
color: var(--vp-c-brand-2) !important;
background-color: var(--vp-c-brand-2) !important;
}

View File

@ -20,6 +20,7 @@ import { ElCollapse, ElCollapseItem, ElTimeline, ElTimelineItem } from 'element-
import './css/style.css';
import './css/iconfont.css';
import './css/element-plus.css';
import './css/animation.css';
import '@nolebase/vitepress-plugin-git-changelog/client/style.css';
import '@nolebase/vitepress-plugin-enhanced-mark/client/style.css';
import '@nolebase/vitepress-plugin-inline-link-preview/client/style.css';

6
package-lock.json generated
View File

@ -6,6 +6,7 @@
"": {
"dependencies": {
"element-plus": "^2.9.11",
"gsap": "^3.13.0",
"vitepress": "^1.6.3"
},
"devDependencies": {
@ -3962,6 +3963,11 @@
"node": ">=6.0"
}
},
"node_modules/gsap": {
"version": "3.13.0",
"resolved": "https://registry.npmmirror.com/gsap/-/gsap-3.13.0.tgz",
"integrity": "sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw=="
},
"node_modules/hachure-fill": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz",

View File

@ -7,6 +7,7 @@
},
"dependencies": {
"element-plus": "^2.9.11",
"gsap": "^3.13.0",
"vitepress": "^1.6.3"
},
"devDependencies": {