网站首页实现
- W_Z_C
- 共 4204 字,阅读约 11 分钟
上篇文章建立了网站的初始框架,本篇文章需要在此基础之上逐步完善模块细节。按照前文提到的网站内容发布流程,首先需要创建三个文件夹,分别用来存放原始的 Markdown 文件、翻译后的国际化文件以及数据库文件。除此之外,我们尽量将源码放到一块,也存放到一个特定的文件夹内,经过整理目录结构如下:
blog
├─ dbs //存放数据库
├─ docs //存放原始 Markdown 文件
├─ i18n //存放国际化需要的文件
├─ public
│ ├─ favicon.ico
│ └─ vercel.svg
├─ src
| ├─ components //网站组件
│ ├─ pages //网站页面
│ │ ├─ index.js
│ │ └─ _app.js
│ └─ styles
│ └─ globals.css
├─ next.config.js
├─ package.json
├─ postcss.config.js
├─ README.md
└─ tailwind.config.js
dbs 用来存放以后使用的数据库文件,docs 用来存放原始 Markdown 文件,i18n 用来存放翻译后的文件,src 用来存放源码文件,现在已经将原来的 pages 和 styles 目录移动到里面,除此之外还新建了一个 components 的文件夹,以后用来存放系统组件。
因为改变了目录结构,所以需要同时修改引用这些目录文件的代码路径:
module.exports = { content: [ "./src/pages/**/*.{js,ts,jsx,tsx}", "./src/components/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {}, }, plugins: [],}
重新运行 npm run dev
,打开 http://localhost:3000/
查看运行是否正常。
1. Nextjs 中的页面系统
Nextjs 中如果想要创建页面,只需要在 pages 文件夹下面添加一个文件,因为 Nextjs 的路由系统是基于文件系统的,所以该文件的路径对应着访问该文件的 URL,例如:如果增加 home.js
文件,则可以通过 http://localhost:3000/home
路径访问。
默认情况下,Nextjs 会预渲染每个页面,这表明 Nextjs 会将 pages 文件下的每个文件生成对应的 HTML 文件,每个生成的 HTML 文件都与该页面最少的 JavaScript 代码相关联,当页面加载时,JavaScript 代码将会运行显示最终的完整页面,这个处理过程被称为水合(hydration)。
Nextjs 初始状态下已经存在了一个 index.js 文件,该文件就是咱们的默认主页,修改它即可完成对主页样式的修改。
传统页面一般可以粗略划分为三个部分:页头、内容和页脚,有些页面还存在侧边栏之类的东西,因为咱们这里是主页,所以暂时不需要。
2. 页头和页脚
页头对于一个网站来说非常重要,因为网站的所有页面都需要显示页头,其主要包含网站的 logo、网站标题、菜单栏等内容。
因为页头会被多个页面复用,因此直接在 components 文件夹下创建一个页头组件,名称叫做 Header.js
。
export function Header() {
return (
<div>页头</div>
)
}
用同样的方式,创建一个页脚:
export function Footer() {
return (
<div>页脚</div>
)
}
然后更改主页代码,引入它们:
import { Header } from "../components/Header"import { Footer } from "../components/Footer"
export default function Home() { return ( <> <Header /> <h1 className="text-center text-3xl font-bold underline"> Hello world! </h1> <Footer /> </> )}
如果一切顺利,访问 http://localhost:3000
可以看到页面上方和下方分别显示 “页头”和“页脚”,这说明网站的组件运行正常,接下来就可以专注实现组件的内容了。
3. 完善页头
其实接下来的工作主要是前端 CSS 方面的内容,没啥好介绍的,可以按照自己的规划写 HTML 和 CSS,或者干脆直接复制下面的代码查看效果即可。因为需要使用动画、弹窗之类的效果,所以要添加额外的第三方组件:
npm install @headlessui/react
除此之外,还需要添加头部使用的图片,特别是网站的 logo。首先咱们在根目录的 public 文件中增加一个 assert 文件夹目录,然后在其内部建立一个 images 文件夹,最后将咱们的网站 logo 文件放进去,当然你也可以不显示 logo 直接显示网站标题,得看你自己的网站样式规划是什么样子的,完成后整个目录的样式如下:
└── public/
├── assert/
│ └── images/
│ └── logo.png
└── favicon.ico
接着修改页头组件代码:
页头代码
import { Fragment, useEffect, useState } from 'react'
import { Dialog, Popover, Tab, Transition } from '@headlessui/react'
import Link from 'next/link'
export function Header() {
const [open, setOpen] = useState(false)
return (
<div className="relative bg-white">
<header className="border-b-2 border-gray-100 w-full fixed bg-white top-0 z-30">
<div className="max-w-7xl mx-auto px-6 md:px-4">
<div className="flex justify-between items-center py-4 lg:py-6 lg:justify-start lg:space-x-10">
<div className="flex justify-start items-center lg:w-0 lg:flex-1">
<img width={64} height={64} src="/assert/images/logo.png" className="inline-block w-auto h-12 md:h-14 transition-transform hover:animate-spin" alt="没事造轮子" />
<span className="sr-only">没事造轮子</span>
<h1 className="inline-block ml-2 text-3xl md:text-4xl">
<Link href="/" passHref>
<a rel="home" aria-current="page">没事造轮子</a>
</Link>
</h1>
</div>
<div className="-mr-2 -my-2 lg:hidden">
<button type="button" className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-primary" aria-expanded="false" onClick={() => setOpen(true)}>
<span className="sr-only">打开菜单</span>
<svg className="h-10 w-10" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<Popover.Group className="hidden lg:flex space-x-10">
<Popover className="relative">
<Popover.Button className="text-gray-600 group rounded-md inline-flex items-center text-xl font-medium hover:text-primary" aria-expanded="false">
<span>教程</span>
<svg className="text-gray-400 ml-2 h-5 w-5 group-hover:text-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</Popover.Button>
<Popover.Panel className="absolute z-10 -ml-4 transform px-2 max-w-md pt-10 w-[28rem] sm:px-0 lg:left-1/2 lg:-translate-x-1/2 lg:ml-0">
<div className="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 overflow-hidden border-t-4 border-primary">
<div className="relative grid gap-6 bg-white px-5 py-6 sm:gap-8 sm:p-8">
<Link href="#" passHref>
<a className="-m-3 p-3 flex items-start rounded-lg hover:bg-gray-50 hover:text-primary">
<div className="ml-4">
<p className="text-base font-medium">
Win32 入门教程
</p>
<p className="mt-1 text-sm text-gray-500">
Windows 操作系统的核心操作接口,独领风骚二十年。
</p>
</div>
</a>
</Link>
<Link href="#" passHref>
<a className="-m-3 p-3 flex items-start rounded-lg hover:bg-gray-50 hover:text-primary">
<div className="ml-4">
<p className="text-base font-medium">
HTML 入门教程
</p>
<p className="mt-1 text-sm text-gray-500">
超文本标记语言,前端网页的骨架,强调语义化。
</p>
</div>
</a>
</Link>
</div>
</div>
</Popover.Panel>
</Popover>
<Popover className="relative">
<Popover.Button className="text-gray-600 group rounded-md inline-flex items-center text-xl font-medium hover:text-primary" aria-expanded="false">
<span>项目</span>
<svg className="text-gray-400 ml-2 h-5 w-5 group-hover:text-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</Popover.Button>
<Popover.Panel className="absolute z-10 -ml-4 transform px-2 max-w-md pt-10 w-60 sm:px-0 lg:left-1/2 lg:-translate-x-1/2 lg:ml-0">
<div className="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 overflow-hidden border-t-4 border-primary">
<div className="relative grid gap-6 bg-white px-5 py-6 sm:gap-8 sm:p-8">
<Link href="#" passHref>
<a className="-m-3 p-3 flex items-start rounded-lg hover:bg-gray-50 hover:text-primary">
<div className="ml-4">
<p className="text-base font-medium">
俄罗斯方块
</p>
<p className="mt-1 text-sm text-gray-500">
</p>
</div>
</a>
</Link>
<Link href="#" passHref>
<a className="-m-3 p-3 flex items-start rounded-lg hover:bg-gray-50 hover:text-primary">
<div className="ml-4">
<p className="text-base font-medium">
方块赛车
</p>
<p className="mt-1 text-sm text-gray-500">
</p>
</div>
</a>
</Link>
</div>
</div>
</Popover.Panel>
</Popover>
<Popover className="relative">
<Popover.Button className="text-gray-600 group rounded-md inline-flex items-center text-xl font-medium hover:text-primary" aria-expanded="false">
<span>码读</span>
<svg className="text-gray-400 ml-2 h-5 w-5 group-hover:text-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</Popover.Button>
<Popover.Panel className="absolute z-10 -ml-4 transform px-2 max-w-md pt-10 w-60 sm:px-0 lg:left-1/2 lg:-translate-x-1/2 lg:ml-0">
<div className="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 overflow-hidden border-t-4 border-primary">
<div className="relative grid gap-6 bg-white px-5 py-6 sm:gap-8 sm:p-8">
<Link href="#" passHref>
<a className="-m-3 p-3 flex items-start rounded-lg hover:bg-gray-50 hover:text-primary">
<div className="ml-4">
<p className="text-base font-medium">
Express 源码刨析
</p>
<p className="mt-1 text-sm text-gray-500">
</p>
</div>
</a>
</Link>
</div>
</div>
</Popover.Panel>
</Popover>
<Popover className="relative">
<Popover.Button className="text-gray-600 group rounded-md inline-flex items-center text-xl font-medium hover:text-primary" aria-expanded="false">
<span>更多</span>
<svg className="text-gray-400 ml-2 h-5 w-5 group-hover:text-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</Popover.Button>
<Popover.Panel className="absolute z-10 -ml-4 transform px-2 max-w-md pt-10 w-[28rem] sm:px-0 lg:right-0 lg:ml-0">
<div className="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 overflow-hidden border-t-4 border-primary">
<div className="relative grid gap-6 bg-white px-5 py-6 sm:gap-8 sm:p-8">
<Link href="#" passHref>
<a className="-m-3 p-3 flex items-start rounded-lg hover:bg-gray-50 hover:text-primary">
<div className="ml-4">
<p className="text-base font-medium">
下载
</p>
<p className="mt-1 text-sm text-gray-500">
博客文章中提到的一些第三方资源、演示程序等内容。
</p>
</div>
</a>
</Link>
<Link href="#" passHref>
<a className="-m-3 p-3 flex items-start rounded-lg hover:bg-gray-50 hover:text-primary">
<div className="ml-4">
<p className="text-base font-medium">
关于
</p>
<p className="mt-1 text-sm text-gray-500">
关于博主、博客的一些基本信息。
</p>
</div>
</a>
</Link>
</div>
</div>
</Popover.Panel>
</Popover>
</Popover.Group>
</div>
</div>
</header>
</div>
)
}
代码非常长,并且还没有包含移动端的代码,这里不多做解读,因为这些都是基础的前端内容不是教程的主要内容,你可以直接粘贴临时使用或者原创自己的网站头部代码。目前的代码只拿 PC 端进行举例,这不会妨碍教程的介绍,毕竟咱们这个教程主要介绍 Nextjs。
这里面其实还有一个细节,例如 text-primary
样式并不是 Tailwind CSS 框架自带的样式,这里运用了 Tailwind 提供的一个功能,你可以在 tailwind.config.js 文件中自定主题样式,下面是我目前使用的配置:
Tailwind 样式配置
const colors = require('tailwindcss/colors')
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx}",
"./src/components/**/*.{js,ts,jsx,tsx}",
],
theme: {
colors: {
transparent: 'transparent',
current: 'currentColor',
black: '#000',
white: '#fff',
gray: colors.slate,
rose: colors.rose,
teal: colors.teal,
sky: colors.sky,
pink: colors.pink,
primary: '#ff4500', //'#F86011', //主题颜色,用于所有控件的首要颜色
// secondary: '#fd5d0a', //提示性颜色,提示动作之类的信息
// accent: '#F86011', //交互性颜色,连接颜色之类的
},
screens: {
'sm': '640px',
'md': '768px',
'lg': '1024px',
'xl': '1280px',
},
extend: {
typography: (theme) => ({
DEFAULT: {
css: {
maxWidth: '42rem',
color: theme('colors.gray.700'),
'h1, h2, h3, h4, h5': {
color: theme('colors.gray.600'),
},
h4: {
fontSize: '1.125em',
},
p: {
textAlign: 'justify',
textJustify: 'inter-ideograph',
},
'ul > li': {
paddingLeft: '1.5em',
},
'ul > li::before': {
width: '0.45em',
height: '0.1em',
top: 'calc(0.875em - 0.0625em)',
left: '0.25em',
borderRadius: 0,
backgroundColor: theme('colors.gray.300'),
},
a: {
color: theme('colors.primary'),
textDecoration: 'none',
'&:hover': {
textDecoration: 'underline',
textUnderlineOffset: '4px'
},
},
code: {
fontWeight: 500,
fontSize: '85%',
padding: '0.2em 0.4em',
borderRadius: '6px',
backgroundColor: theme('colors.gray.100')
},
'code::before': {
content: 'none',
},
'code::after': {
content: 'none',
},
'blockquote p:first-of-type::before': {
content: 'none',
},
'blockquote p:last-of-type::after': {
content: 'none',
},
details: {
margin: '0.5rem 0px',
padding: '0.5rem 1rem',
backgroundColor: theme('colors.gray.100'),
border: '1px solid',
borderColor: theme('colors.gray.300'),
borderRadius: 3,
},
pre: {
// color: theme('colors.black'),
// borderWidth: 0,
// // borderColor: theme('colors.black'),
// // backgroundColor: 'none',
// backgroundColor: theme('colors.gray.100'),
// borderRadius: 3,
// fontSize: '85%',
paddingTop: 0,
marginTop: '1em',
marginBottom: '1em',
},
table: {
fontSize: theme('fontSize.sm')[0],
lineHeight: theme('fontSize.sm')[1].lineHeight,
},
thead: {
color: theme('colors.gray.600'),
borderBottomColor: theme('colors.gray.200'),
},
'thead th': {
paddingTop: 0,
fontWeight: theme('fontWeight.semibold'),
},
'tbody tr': {
borderBottomColor: theme('colors.gray.200'),
},
'tbody tr:last-child': {
borderBottomWidth: '1px',
},
'tbody code': {
fontSize: theme('fontSize.xs')[0],
},
}
}
}),
fontFamily: {
sans: ['Inter var', ...defaultTheme.fontFamily.sans],
// mono: ['Fira Code VF', ...defaultTheme.fontFamily.mono],
source: ['Source Sans Pro', ...defaultTheme.fontFamily.sans],
'ubuntu-mono': ['Ubuntu Mono', ...defaultTheme.fontFamily.mono],
system: defaultTheme.fontFamily.sans,
flow: 'Flow',
}
},
},
plugins: [
require('@tailwindcss/typography'),
],
}
代码中重新定义了一些可能用到的颜色属性,并设置了屏幕断点,最重要的是引入了 @tailwindcss/typography
插件,并简单修改了插件默认的文本样式。
在添加完代码后,不要忘记安装 @tailwindcss/typography
插件,否则运行会报找不到模块的错误:
npm install @tailwindcss/typography
该插件主要用于文章排版的默认样式,在以后的文章显示章节中会具体介绍使用方法。到目前为止网站的头部算是初步搭建完毕,如果一切顺利,你已经可以在浏览器端查看网站头部的效果了。
4. 完善页脚
接下来继续完善页脚部分,页脚部分相对来说比较简单,至少目前我并不想把页脚的样式弄的很重,所以基本上就是一行代码而已:
export function Footer({trans}) {
return (
<footer className="py-8 border-t">
<p className="text-left text-base max-w-7xl px-6 mx-auto">
<span>{`Copyright © 2020 - ${(new Date).getFullYear()} ${trans.Title} | `}</span>
<a href="https://beian.miit.gov.cn/" target="_blank" rel="nofollow noreferrer noopener">浙ICP备2021026646号 | </a>
<span>
<img className="inline-block" alt="beiantubiao" width="16" height="16" src="/assert/images/1631844241-beiantubiao.png"></img>
<a href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=33078202001694" target="_blank" rel="nofollow noreferrer noopener">浙公网安备 33078202001694号</a>
</span>
</p>
</footer>
)
}
这里只显示网站的名称和备案信息,都是最简单的 HTML 代码,显示的效果还算可以:
5. Hero 模块
Hero 模块主要用于网站的头部,一般被放在网站的首页顶部,大尺寸横幅展示,可以有效的吸引用户的目光。咱们这里还是低调一点,只显示一个动画和文字即可。
首先在 components 文件夹下建立 Hero/index.js
文件,内容如下:
Hero 模块
import Lottie from 'lottie-react'
import animationData from './girl-studying-on-laptop.json'
import Link from 'next/link'
export function Hero() {
return (
<div className="py-20 md:py-32">
<section className="container md:flex mx-auto">
<div className="w-full mt-10 md:w-1/2">
<Lottie
animationData={animationData}
loop={true}
autoPlay={true}
/>
</div>
<div className="w-full mt-10 md:w-1/2">
<h2 className="text-6xl text-center leading-normal md:leading-relaxed md:text-[4rem] lg:text-[5rem]">
<span>学习、实战、总结、</span>
<span className="relative inline-block overflow-visible">
<span className="font-black z-10 relative">分享</span>
<svg className="text-primary absolute -translate-y-1/2 -translate-x-1/2 top-1/2 left-1/2 h-[calc(100%)] w-[calc(100%+2rem)]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none"><path fill="none" stroke="currentColor" strokeWidth="9" d="M7.7,145.6C109,125,299.9,116.2,401,121.3c42.1,2.2,87.6,11.8,87.3,25.7"></path></svg>
</span>
</h2>
<div className="text-center mt-16">
<Link href="#tutorial-hero" passHref>
<a className="inline-block py-4 px-14 rounded-md bg-primary transform duration-500 hover:scale-110 motion-reduce:transform-none">
<span className="flex text-xl text-white font-bold">
<svg className="w-4 mr-2 fill-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M381.2 172.8C377.1 164.9 368.9 160 360 160h-156.6l50.84-127.1c2.969-7.375 2.062-15.78-2.406-22.38S239.1 0 232 0h-176C43.97 0 33.81 8.906 32.22 20.84l-32 240C-.7179 267.7 1.376 274.6 5.938 279.8C10.5 285 17.09 288 24 288h146.3l-41.78 194.1c-2.406 11.22 3.469 22.56 14 27.09C145.6 511.4 148.8 512 152 512c7.719 0 15.22-3.75 19.81-10.44l208-304C384.8 190.2 385.4 180.7 381.2 172.8z"/></svg>
<span>开始学习</span>
</span>
</a>
</Link>
</div>
</div>
</section>
</div>
)
}
该模块使用了一个第三方的组件 lottie-react
,其主要用于显示 Lottie 动画。Lottie 动画主要使用 JSON 来描述动画内容,代码中使用的 girl-studying-on-laptop.json
文件就是 Lottie 动画的核心数据,你可以在网上找一些开源免费的动画模板用在自己网站上,也可以使用 AE 之类的工具手工原创。
6. 教程列表模块
Hero 模块下面显示网站的核心内容,在本教程中则直接显示一个教程列表。代码如下:
教程列表模块
import Link from 'next/link'
export function TutorialList() {
return (
<>
<div className="text-center py-5 text-gray-600">
<h2 id="tutorial-hero" className="text-5xl md:text-6xl">技术教程</h2>
<p className="text-xl p-5">专注于某项技术的系统性课程,从零开始,深入简出。</p>
</div>
<section className="text-center">
<div className="flex flex-col max-w-6xl mx-auto justify-center px-4 md:space-x-8 md:flex-row ">
<div className="shadow-lg my-8 py-8 px-4 rounded-lg md:w-1/3">
<div className="flex flex-col text-gray-600 px-4 space-y-8">
<h3 className="text-5xl font-semibold">Win32</h3>
<p className="text-xl">Windows 系统的核心操作接口,独领风骚二十年。</p>
<svg className="h-36 mx-auto text-primary" aria-hidden="true" focusable="false" data-prefix="fab" data-icon="windows" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M0 93.7l183.6-25.3v177.4H0V93.7zm0 324.6l183.6 25.3V268.4H0v149.9zm203.8 28L448 480V268.4H203.8v177.9zm0-380.6v180.1H448V32L203.8 65.7z"></path></svg>
<div className="mx-auto">
<Link href="/windows-bian-cheng-kai-fa" passHref>
<a className="inline-block py-4 px-10 rounded-md bg-primary hover:shadow-xl">
<span className="flex text-xl font-bold text-white ">
<span>开始学习</span>
</span>
</a>
</Link>
</div>
</div>
</div>
<div className="shadow-lg my-8 py-8 px-4 rounded-lg md:w-1/3">
<div className="flex flex-col text-gray-600 px-4 space-y-8">
<h3 className="text-5xl font-semibold">SDL2</h3>
<p className="text-xl">开源的多媒体跨平台开发库,纯 C 接口,易于上手。</p>
<svg className="h-36 mx-auto text-primary" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="dice-d20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M20.04 317.3C18 317.3 16 315.8 16 313.3V150.5c0-2.351 1.91-4.012 4.001-4.012c.6882 0 1.396 .18 2.062 .5748l76.62 45.1l-75.28 122.3C22.59 316.8 21.31 317.3 20.04 317.3zM231.4 405.2l-208.2-22.06c-4.27-.4821-7.123-4.117-7.123-7.995c0-1.401 .3725-2.834 1.185-4.161L122.7 215.1L231.4 405.2zM31.1 420.1c0-2.039 1.508-4.068 3.93-4.068c.1654 0 .3351 .0095 .5089 .0291l203.6 22.31v65.66C239.1 508.6 236.2 512 232 512c-1.113 0-2.255-.2387-3.363-.7565L34.25 423.6C32.69 422.8 31.1 421.4 31.1 420.1zM33.94 117.1c-1.289-.7641-1.938-2.088-1.938-3.417c0-1.281 .6019-2.567 1.813-3.364l150.8-98.59C185.1 10.98 187.3 10.64 188.6 10.64c4.32 0 8.003 3.721 8.003 8.022c0 1.379-.3788 2.818-1.237 4.214L115.5 165.8L33.94 117.1zM146.8 175.1l95.59-168.4C245.5 2.53 250.7 0 255.1 0s10.5 2.53 13.62 7.624l95.59 168.4H146.8zM356.4 207.1l-100.4 175.7L155.6 207.1H356.4zM476.1 415.1c2.422 0 3.93 2.029 3.93 4.068c0 1.378-.6893 2.761-2.252 3.524l-194.4 87.66c-1.103 .5092-2.241 .7443-3.35 .7443c-4.2 0-7.994-3.371-7.994-7.994v-65.69l203.6-22.28C475.7 416 475.9 415.1 476.1 415.1zM494.8 370.9C495.6 372.3 496 373.7 496 375.1c0 3.872-2.841 7.499-7.128 7.98l-208.2 22.06l108.6-190.1L494.8 370.9zM316.6 22.87c-.8581-1.395-1.237-2.834-1.237-4.214c0-4.301 3.683-8.022 8.003-8.022c1.308 0 2.675 .3411 4.015 1.11l150.8 98.59c1.211 .7973 1.813 2.076 1.813 3.353c0 1.325-.6488 2.649-1.938 3.429L396.5 165.8L316.6 22.87zM491.1 146.5c2.091 0 4.001 1.661 4.001 4.012v162.8c0 2.483-2.016 4.006-4.053 4.006c-1.27 0-2.549-.5919-3.353-1.912l-75.28-122.3l76.62-45.1C490.6 146.7 491.3 146.5 491.1 146.5z"></path></svg>
<div className="mx-auto">
<Link href="/sdl2-you-xi-kai-fa-zui-xiao-zhi-shi-zhan" passHref>
<a className="inline-block py-4 px-10 rounded-md bg-primary hover:shadow-xl">
<span className="flex text-xl font-bold text-white">
<span>开始学习</span>
</span>
</a>
</Link>
</div>
</div>
</div>
<div className="shadow-lg my-8 py-8 px-4 rounded-lg md:w-1/3">
<div className="flex flex-col text-gray-600 px-4 space-y-8">
<h3 className="text-5xl font-semibold">CSS</h3>
<p className="text-xl">前端学习的必备知识,控制网站样式的专用语言。</p>
<svg className="h-36 mx-auto text-primary" aria-hidden="true" focusable="false" data-prefix="fab" data-icon="css3-alt" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M0 32l34.9 395.8L192 480l157.1-52.2L384 32H0zm313.1 80l-4.8 47.3L193 208.6l-.3 .1h111.5l-12.8 146.6-98.2 28.7-98.8-29.2-6.4-73.9h48.9l3.2 38.3 52.6 13.3 54.7-15.4 3.7-61.6-166.3-.5v-.1l-.2 .1-3.6-46.3L193.1 162l6.5-2.7H76.7L70.9 112h242.2z"></path></svg>
<div className="mx-auto">
<a href="#" className="inline-block py-4 px-10 rounded-md bg-primary hover:shadow-xl">
<span className="flex text-xl font-bold text-white">
<span>开始学习</span>
</span>
</a>
</div>
</div>
</div>
</div>
</section>
</>
)
}
最终的显示效果如下:
7. 最新文章模块
主页的最后则显示博客的最新文章,因为需要涉及到文章的动态加载,所以这里先初始化大致的框架,具体代码等以后再完善:
export function RecentPosts({ posts }) {
return (
<>
<div className="text-center pt-24 pb-16 text-gray-600">
<h2 className="text-5xl md:text-6xl">最新文章</h2>
</div>
<section className="flex flex-wrap text-gray-600 max-w-screen-lg mx-auto mb-10">
文章列表。。。
</section>
</>
)
}
创建完这些模块之后,不要忘记修改首页代码:
import { Header } from "../components/Header"
import { Footer } from "../components/Footer"
import { Hero } from "../components/Hero"
import { TutorialList } from "../components/TutorialList"
import { RecentPosts } from "../components/RecentPosts"
export default function Home() {
return (
<>
<Header />
<Hero />
<TutorialList />
<RecentPosts />
<Footer />
</>
)
}
打完收工!
8. 总结
到此为止,第一轮的首页迭代已经完成,其实核心内容基本和 Nextjs 无关,只是单纯的运用 CSS 和 HTML 写网页而已,所以文章并没有进行过多的介绍,咱们的目的还是 Nextjs,但是你又不能不搞,毕竟最终的任务是用 Nextjs 搭建一个完整的网站。
本篇文章的重点在于初始化目录的结构,拆分首页各个模块,因为页首和页脚都可以复用,所以这里将它们全部封装为组件,这些组件可以无缝兼容的运用在其它页面上,快捷方便。