完成顶部导航组件

This commit is contained in:
宇阳
2024-08-22 20:01:20 +08:00
parent 1651d5edb5
commit 10c3629052
12 changed files with 271 additions and 10 deletions

10
package-lock.json generated
View File

@@ -11,6 +11,7 @@
"next": "14.2.5",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.3.0",
"sass": "^1.77.8",
"typed.js": "^2.1.0"
},
@@ -1294,6 +1295,15 @@
"react": "^18.3.1"
}
},
"node_modules/react-icons": {
"version": "5.3.0",
"resolved": "https://registry.npmmirror.com/react-icons/-/react-icons-5.3.0.tgz",
"integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==",
"license": "MIT",
"peerDependencies": {
"react": "*"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",

View File

@@ -12,6 +12,7 @@
"next": "14.2.5",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.3.0",
"sass": "^1.77.8",
"typed.js": "^2.1.0"
},

View File

@@ -1,4 +1,4 @@
import type { Metadata } from "next";
import Header from '@/components/Header'
// 加载样式文件
import "@/styles/index.scss";
@@ -11,6 +11,7 @@ const LXGWWenKai = localFont({
display: 'swap',
})
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "宇阳 - 花有重开日,人无再少年!",
description: "Generated by create next app",
@@ -19,7 +20,10 @@ export const metadata: Metadata = {
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<body className={LXGWWenKai.className}>{children}</body>
<body className={LXGWWenKai.className}>
<Header />
{children}
</body>
</html>
);
}

View File

@@ -6,7 +6,9 @@ export default function Home() {
return (
<>
<Swiper>
{/* 星空背景组件 */}
<Starry />
{/* 打字机组件 */}
<Typed className="absolute top-[40%] left-[50%] transform -translate-x-1/2 w-[80%] text-center text-white text-[30px] custom_text_shadow"></Typed>
</Swiper>
</>

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,89 @@
@import "@/styles/var.scss";
.HeaderComponent {
.header {
position: fixed;
top: 0;
width: 100%;
height: 60px;
backdrop-filter: blur(5px);
transition: background-color $move;
z-index: 999;
&::after {
content: "";
display: block;
width: 100%;
height: 0;
background: linear-gradient(#fff, transparent 70%);
transition: background $move;
}
// 二级导航
.two {
display: none;
overflow: hidden;
position: absolute;
top: 50px;
width: 100%;
border-radius: $round;
background-color: #f9f9f9;
box-shadow: 0 12px 32px rgba(0, 0, 0, .1), 0 2px 6px rgba(0, 0, 0, .08);
.two_item {
.two_item_nav {
position: relative;
display: inline-block;
width: 100%;
padding: 10px;
padding-left: 10px;
font-size: 15px;
box-sizing: border-box;
color: #666;
transition: all $move;
// 鼠标经过的小横线
&::after {
content: "";
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
width: 0;
height: 3px;
background-color: $color;
transition: width $move;
}
}
// 鼠标经过二级导航的效果
&:hover .two_item_nav {
color: $color !important;
background-color: #f2f2f2;
padding-left: 30px;
&:hover::after {
width: 10px;
}
}
}
}
// 鼠标经过哪个,就让哪个二级导航显示
&:hover .two {
display: block;
}
}
.bg {
border-bottom: 1px solid #eee;
background-color: rgba(255, 255, 255, 0.9);
transition: all $move;
&::after {
content: "";
height: 30px;
transition: height $move;
}
}
}

View File

@@ -0,0 +1,134 @@
"use client"
import React, { useState, useEffect } from 'react';
import Link from 'next/link';
import lightLogo from '@/assets/image/light_logo.png';
import darkLogo from '@/assets/image/dark_logo.png';
import { IoIosArrowDown } from "react-icons/io";
import "./index.scss"
const Header = () => {
const cateList = [
{
"id": 1,
"name": "开发笔记",
"url": "/",
"mark": "kfbj",
"icon": "🎉",
"level": 0,
"children": []
},
{
"id": 2,
"name": "生活随笔",
"url": "/",
"mark": "shsb",
"icon": "✍️",
"level": 0,
"children": []
},
{
"id": 4,
"name": "大前端",
"url": "http://127.0.0.1:5000",
"mark": "dqd",
"icon": "🎉",
"level": 0,
"children": [
{
"id": 5,
"name": "前端",
"url": "/",
"mark": "qd",
"icon": "?",
"level": 4,
"children": []
},
{
"id": 7,
"name": "Java",
"url": "/",
"mark": "java",
"icon": "?",
"level": 4,
"children": []
},
{
"id": 9,
"name": "Python",
"url": "/",
"mark": "python",
"icon": "?",
"level": 4,
"children": []
}
]
}
];
const [isScrolled, setIsScrolled] = useState(false);
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 100);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<div className='HeaderComponent'>
<div className={`header ${isScrolled ? 'bg' : ''}`}>
<div className="w-[1500px] mx-auto flex items-center h-full">
<ul className="flex items-center h-full">
<li className="relative">
<Link href="/" className="flex items-center">
<img
src={!isScrolled ? darkLogo.src : lightLogo.src}
alt="Logo"
className="h-10 pr-5 transition-transform hover:scale-90"
/>
</Link>
</li>
<li className="relative group">
<Link href="/" className={`text-[15px] px-5 py-4 ${isScrolled ? 'text-[#333]' : 'text-white'} transition-colors group-hover:text-primary`}>
💎
</Link>
</li>
{cateList.map(one => (
<li key={one.id} className="relative group">
<Link href={one.url} className={`text-[15px] px-5 py-4 ${isScrolled ? 'text-[#333]' : 'text-white'} transition-colors flex items-center group-hover:text-primary`}>
{one.icon} {one.name}
{one.children.length > 0 && (
<IoIosArrowDown className="ml-2" />
)}
</Link>
{one.children.length > 0 && (
// <ul className="absolute left-0 w-full bg-white shadow-lg rounded-md hidden group-hover:block">
<ul className="two">
{one.children.map(two => (
<li key={two.id} className="two_item">
<Link href={two.url} className="two_item_nav">
{two.name}
</Link>
</li>
))}
</ul>
)}
</li>
))}
</ul>
</div>
</div>
</div>
);
};
export default Header;

View File

@@ -3,7 +3,7 @@
import { useEffect } from 'react';
import './index.scss';
const StarrySky = () => {
const StarrySky: React.FC = () => {
useEffect(() => {
/*星星的密集程度,数字越大越多*/
const stars = 800;
@@ -14,10 +14,10 @@ const StarrySky = () => {
for (let i = 0; i < stars; i++) {
const star = document.createElement('div');
star.classList.add('star_starrySky');
starsContainer.appendChild(star);
starsContainer?.appendChild(star);
}
const starElements = document.querySelectorAll('.star_starrySky');
const starElements = document.querySelectorAll<HTMLElement>('.star_starrySky');
starElements.forEach((starElement) => {
const s = 0.2 + Math.random() * 1;
const curR = r + Math.random() * 300;
@@ -36,4 +36,4 @@ const StarrySky = () => {
);
};
export default StarrySky;
export default StarrySky;

View File

@@ -1,3 +1,8 @@
body {
height: 2000px;
background-color: #f9f9f9;
}
.custom_text_shadow {
text-shadow: 0 0.1875rem 0.3125rem #1c1f21;
}

15
src/styles/var.scss Normal file
View File

@@ -0,0 +1,15 @@
// 版心
$w: 1200px;
// 色彩
$color: var(--color, #539dfd); // 主色调
$assistColor: var(--assistColor, #539dfd60); // 辅助色调
// 过渡效果
$move: 0.3s;
// 圆角效果
$round: 5px;
// 阴影效果
$boxShadow: 0 2px 8px rgba(186, 186, 186, 0.15);

View File

@@ -8,10 +8,11 @@ const config: Config = {
],
theme: {
extend: {
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
colors: {
primary: '#539dfd', // 添加自定义颜色
},
transitionDuration: {
'DEFAULT': '300ms', // 添加默认过渡时间为0.3秒
},
},
},