React项目案例-影视资源网站

案例项目基本需求分析

  • 前端页面布局使用Chakra-UI

  • 后端服务使用Next.js

  • 样式定义采用CSS-in-JS的方案,使用emotion库(需要在Next.js扩展babel配置)

  • Next.js 与Chakra-UI结合使用实现项目页面的功能

  • 首页(列表页)的轮播图,以及影视资源列表展示

  • 影视详情页使用基因动态路由的静态生成

项目代码初始化

运行安装依赖包命令:

npm init next-app aimovie
cd aimovie
#npm i @chakra-ui/react
#npm i @chakra-ui/react@^1 @emotion/react@^11 @emotion/styled@^11 framer-motion@^6
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
npm i react-icons
npm i @babel/core @emotion/babel-preset-css-prop -D
{
  "name": "aimovie",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@babel/core": "^7.21.0",
    "@chakra-ui/react": "^2.5.1",
    "@emotion/react": "^11.10.6",
    "@emotion/styled": "^11.10.6",
    "framer-motion": "^10.2.5",
    "next": "13.2.4",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-icons": "^4.8.0"
  }
}

创建pages目录下的 _app.js 文件:

// import '@/styles/globals.css'
// pages/_app.js
import { ChakraProvider, CSSReset } from '@chakra-ui/react'
import theme from '../chakra'

function App ({ Component, pageProps }) {
  return (
    <ChakraProvider theme={theme}>
      <CSSReset />
      <Component {...pageProps} />
    </ChakraProvider>
  )
}

export default App

创建 .babelrc 文件作为babel的配置文件:(在新版的next.js中不需要配置,默认开启了cssProp,否则会产生next/font冲突)

{
  "presets": [
    "next/babel",
    "@emotion/babel-preset-css-prop"
  ]
}

页面组件规划与布局实现

实现页面头部组件

头部组件包含三部分:左侧的登录注册按钮组件 中间的网站logo 右边的搜索按钮。

布局规划:左浮动 有浮动 中间logo始终居中。

创建components文件夹,用于存放非页面层级的组件。

头部组件基本布局:

import React from 'react'
import { Box, Button, Container, Image } from '@chakra-ui/react'
import { FaSearch, FaSignInAlt, FaUserAlt } from 'react-icons/fa'
import styled from '@emotion/styled'
import { css } from '@emotion/react'
const SignInAndJoin = styled.div`
  height: 52px;
  line-height: 52px;
  color: #fff;
  border-left: 1px solid #393939;
  border-right: 1px solid #393939;
  padding: 0 6px;
  float: left;
`
const logo = css`
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 140px;
  height: auto;
`

const Search = styled.a`
  float: right;
  height: 52px;
  border-left: 1px solid #393939;
  border-right: 1px solid #393939;
  color: #fff;
  padding: 0 10px;
  display: flex;
  align-items: center;
`
export default function Header () {
  return (
    <Box h='52px' bgColor='#202020' borderBottom='1px solid #393939'>
      <Container pos='relative' h='52px' maxW='1200px'>
        <SignInAndJoin>
          <Button
            mr='5px'
            leftIcon={<FaSignInAlt />}
            colorScheme='teal'
            variant='solid'
          >
            登录
          </Button>
          <Button
            leftIcon={<FaUserAlt />}
            colorScheme='orange'
            variant='outline'
          >
            注册
          </Button>
        </SignInAndJoin>
        <Image css={logo} src='/images/logo.png' />
        <Search>
          <FaSearch size='16px' title='搜索' />
        </Search>
      </Container>
    </Box>
  )
}

实现导航组件布局

import React from 'react'
import { Box, HStack, Link } from '@chakra-ui/react'
import NextLink from 'next/link'
import styles from '@/styles/Navigation.module.css'
import { useRouter } from 'next/router'

export default function Navigation () {
  const router = useRouter()
  const isActiveLink = href => router.asPath === href
  return (
    <Box height='52px' bgColor='#202020' color='#fff'>
      <HStack h='100%' spacing={3} justifyContent='center' alignItems='center'>
        <Link
          className={`${styles.navlink} ${
            isActiveLink('/') ? styles.active : ''
          }`}
          href='/'
          as={NextLink}
        >
          影片
        </Link>
        <Link
          className={`${styles.navlink} ${
            isActiveLink('/1') ? styles.active : ''
          }`}
          href='/1'
          as={NextLink}
        >
          漫画
        </Link>
        <Link
          className={`${styles.navlink} ${
            isActiveLink('/2') ? styles.active : ''
          }`}
          href='/2'
          as={NextLink}
        >
          电影
        </Link>
        <Link
          className={`${styles.navlink} ${
            isActiveLink('/3') ? styles.active : ''
          }`}
          href='/3'
          as={NextLink}
        >
          电视
        </Link>
        <Link
          className={`${styles.navlink} ${
            isActiveLink('/4') ? styles.active : ''
          }`}
          href='/4'
          as={NextLink}
        >
          新闻资讯
        </Link>
      </HStack>
    </Box>
  )
}

实现轮播图组件布局

这里使用到一个第三方组件react-responsive-carousel

npm i react-responsive-carousel
import React from 'react'
import { Carousel } from 'react-responsive-carousel'
import 'react-responsive-carousel/lib/styles/carousel.min.css'
import { css } from '@emotion/react'
import { Box, Stack, Heading, Text, Button } from '@chakra-ui/react'
import styled from '@emotion/styled'
const CarouselItem = styled.div`
  position: relative;
  & > div {
    position: absolute;
    left: 50%;
    top: 0;
    transform: translateX(-50%);
    color: #fff;
    width: 80%;
    height: 100%;
    max-width: 1200px;
    text-align: left;
    & > h2 {
      width: 450px;
    }
    & > p {
      margin: 15px 0;
      width: 450px;
    }
  }
  & > img {
    filter: brightness(50%);
  }
`
const swiperContainer = css`
  & > .carousel-root {
    position: relative;
    & > .carousel:last-child {
      position: absolute;
      left: 0;
      bottom: 0;
      & > .thumbs-wrapper > .thumbs {
        display: flex;
        justify-content: center;
      }
    }
  }
`

export default function Swiper () {
  return (
    <Box css={swiperContainer}>
      <Carousel
        // autoPlay
        infiniteLoop
        emulateTouch
        showArrows={false}
        showIndicators={false}
        showStatus={false}
      >
        <CarouselItem>
          <img src='/images/1.jpg' />
          <Stack justifyContent='center'>
            <Heading as='h1' size={'lg'}>
              King In Black
            </Heading>
            <Text>
              The next shock chapter in Donny Cates and Ryan Stegman hello look
              at me! shock chapter in Donny Cates and Ryan Stegman hello look at
              me!
            </Text>
            <Button colorScheme='red' w='150px'>
              Go To This
            </Button>
          </Stack>
        </CarouselItem>
        <CarouselItem>
          <img src='/images/2.jpg' />
          <Stack justifyContent='center'>
            <Heading as='h1' size={'lg'}>
              King In Black
            </Heading>
            <Text
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值