실습: 초급 React 모방 Xiaohongshu 홈페이지

이미지.png

머리말

리액트 소개

  React 는 주로 UI 구축을 위한 사용자 인터페이스 구축을 위한 JavaScript 라이브러리입니다. React는 JSX(JavaScript의 확장) 및 구성 요소와 같은 고성능 및 기능을 가지고 있습니다. 컴포넌트화의 개념은 React에서 널리 사용되며, 컴포넌트를 구성하여 코드를 잘 재사용할 수 있습니다. 또한 React 의 선언적 디자인과 DOM 에뮬레이션으로 인해 효율적이고 유연합니다.

프로젝트 설명

소셜 및 전자 상거래   에 위치하는 앱으로서 Xiaohongshu 는 최근 몇 년 동안 점점 더 많은 관심을 받고 있으며 사용자 기반도 확대되고 있습니다. Xiaohongshu의 사용자로서 최근 React에 대한 지식과 결합하여 Xiaohongshu홈페이지를 모방하기 위해 React 를 사용할 생각이 있습니다. 이 프로젝트는 Xiaohongshu 홈페이지의 기본 페이지를 구현하고 프로젝트 디스플레이 및 실제 전투로 이동합니다.

완제품 전시

여기 이미지가 있습니다

이미지.png


실수했어, 돌아와

QQ 화면 녹화 20220705164119.gif


프로젝트 전투

첫 단계

  Vscode에서 React 프로젝트 만들기 프로젝트 를 만드는 방법에는 여러 가지가 있습니다. 공식 스캐폴딩 create-react-app 또는 Webpack을 사용하여 생성합니다. 여기서는 Vitejs 방법을 사용하여 다른 방법보다 훨씬 빠르게 만듭니다. 이에 관심이 있으시면 나중에 Vite와 Webpack에 대한 글을 작성 하겠습니다 .

폴더 구성

  프로젝트가 생성되면 다음 단계는 관련 파일 및 관련 중복 파일의 코드를 정리하고 프로젝트에서 가장 기본적인 폴더를 생성하는 것입니다.

  • 네트워크 요청을 위한 api 폴더
  • 자산 폴더는 아이콘 및 그림과 같은 일부 정적 리소스를 저장하는 데 사용됩니다.
  • 페이지용 페이지 폴더
  • 재사용 가능한 구성 요소를 위한 compmtents 폴더

  자세한 파일 디렉토리는 다음과 같습니다.

이미지.png

종속성 설치

  相关文件夹配置完成后,可以开始安装项目需要的依赖

  • npm i axios   用于获取后端数据
  • npm i react-router react-router-dom    用于项目路由跳转
  • npm i styled-components   用于实现Css in JS
  • npm i antd-mobile   一个好用的UI组件库
  • npm i classname   用于添加多个类名

  安装成功后如下所示:

이미지.png

组件及页面分析

路由介绍

  在以上工作完成后,接下来就是搭建相关路由了,路由在项目中是十分重要的。Route【路由】可以理解为现实中路由器后面的接口,Routes【路由器】可以理解为现实的路由器用来管理路由。在此项目中,我设置了如下几个路由:

const Home = lazy(() => import('./pages/Home'))
const Mine = lazy(() => import('./pages/Mine'))
const Message = lazy(() => import('./pages/Message'))
const Shop = lazy(() => import('./pages/Shop'))
const Choose = lazy(() => import('./pages/Choose'))

<Routes>
        <Route path="/" element={<Home/>}></Route>
        <Route path="/home" element={<Home/>}></Route>
        <Route path="/mine" element={<Mine/>}></Route>
        <Route path="/message" element={<Message/>}></Route>
        <Route path="/shop" element={<Shop/>}></Route>
        <Route path='/choose' element={<Choose />}></Route>
</Routes>

  路由搭建需要注意以下几点:

  • main.jsx中引入{BrowserRouter}方能正常使用
  • 使用路由懒加载,可提升加载速度,需引入{Suspense}

이미지.png

  • 若出现某个页面跳转后不显示底部导航栏,可以通过简单的条件判断和{useLocation}接受传来的值来实现。比如如下所示:
import {useLocation} from 'react-router-dom'

const {pathname}=useLocation()
if (pathname == '/choose') return

数据请求

  在此项目中采用的是fastmock来请求与管理数据,然后在api文件夹中创建request.js来获取数据。后续在相关页面中引入即可。

이미지.png

import axios from 'axios'

export const Getlist = () =>   
axios.get
('https://www.fastmock.site/mock/33e7fec4e60b54344eaa2c59a55b379d/red_book/red_book/list')
export const Getfood = () =>   
axios.get
('https://www.fastmock.site/mock/33e7fec4e60b54344eaa2c59a55b379d/red_book/red_book/food')

底部导航栏

QQ录屏20220705171130.gif


  底部导航栏通过路由的切换来实现。上面已经讲过一些路由知识,在此就不做过多描述。在components文件夹中创建Footer组件,用于底部导航栏。在此注意点击中间加号跳转后底部导航栏不会一起跳转,因此需要做相关判断来实现跳转新页面,源码如下:
Footer.jsx

import React from 'react'
import {Link,useLocation} from 'react-router-dom'
import {FooterWrapper} from './style' 
import classnames from 'classnames'
import { Badge } from 'antd-mobile'

function Footer(props) {
  const {pathname}=useLocation()
  if (pathname == '/choose') return
  return (
    <FooterWrapper>
      <Link to="/" className={classnames({active:pathname == '/'})}>
      <span>首页</span>
      </Link>
      <Link to="/shop" className={classnames({active:pathname == '/shop'})}>
      <span>商城</span>
      </Link>
      <Link to="/choose" className={classnames({active:pathname == '/choose'})}>
      <span><i className="iconfont icon-Addtianjia3"></i></span>
      </Link>
      <Link to="/message" className={classnames({active:pathname == '/message'})}>
      <Badge content='5'><span>消息</span></Badge>
      </Link>
      <Link to="/mine" className={classnames({active:pathname == '/mine'})}>
      <span>我</span></Link>
    </FooterWrapper>
  )
}

export default Footer

  主页面引入Footer,部分源码如下:

<>
<Routes>
        <Route path="/" element={<Home/>}></Route>
        <Route path="/home" element={<Home/>}></Route>
        <Route path="/mine" element={<Mine/>}></Route>
        <Route path="/message" element={<Message/>}></Route>
        <Route path="/shop" element={<Shop/>}></Route>
        <Route path='/choose' element={<Choose />}></Route>
</Routes>
<Footer />
</>

顶部导航栏

QQ录屏20220705171330.gif


  상단 탐색 모음은 탭 모음을 사용하여 콘텐츠를 전환합니다. 여기에 두 개의 탐색 모음이 있으며 검색 페이지 아래에도 탐색 모음이 있으므로 탐색 모음 효과를 두 번 구현해야 합니다. 두 탐색 모음의 구현은 매우 간단하며 소스 코드는 다음과 같습니다.
Home .jsx

import React, { useState,useEffect } from "react";
import { Tabs,Popup } from 'antd-mobile'
import Care from './Care'
import Find from './Find'
import City from './City'
import Search from '../Search'
import Daily from '../Daily'
import './style.css'

 const Home = () =>{
    const [visible1, setVisible1] = useState(false)
    const [visible2, setVisible2] = useState(false)
    return(
        <div>
            <Tabs defaultActiveKey='find' style={
                {'--active-line-color':'#ed2b43','--active-title-color':'#000000'}}>
                <Tabs.Tab title='关注' key='care'>
                    <Care/>
                </Tabs.Tab>
                <Tabs.Tab title='发现' key='find'>
                    <Find/>
                </Tabs.Tab>
                <Tabs.Tab title='城市' key='city'>
                    <City/>
                </Tabs.Tab>
            </Tabs> 
            
            <span
              onClick={() => {
                setVisible1(true)
              }}
            >
              <i className="iconfont icon-yuzhouxingqiu-12"></i>
            </span>
            <Popup
              visible={visible1}
              onMaskClick={() => {
                setVisible1(false)
              }}
              position='left'
              bodyStyle={{ height: '100%',width:'100%' }}
            >
              {<Daily />}
            </Popup>
            <span
              onClick={() => {
                setVisible2(true)
              }}
            >
              <i className="iconfont icon-sousuo"></i>
            </span>
            <Popup
              visible={visible2}
              onMaskClick={() => {
                setVisible2(false)
              }}
              position='right'
              bodyStyle={{ height: '100%',width:'100%' }}
            >
              {<Search />}
            </Popup>
        </div>
    )
 }

 export default Home

찾기.jsx

import React, { useState,useEffect } from "react";
import { Tabs,Collapse,SpinLoading } from 'antd-mobile'
import Recommend from '../../Recommend'
import Video from '../../Video'
import Liver from '../../Liver'
import Food from '../../Food'
import { Getlist } from '../../../api/request'
import { Getfood } from "../../../api/request"
import './style.css'

 const Find = () =>{

  const [list,SetList] = useState([])
    useEffect(()=>{
      (async() => {
        let { data } = await Getlist()
        SetList(data)
      })()
    },[])
    const [food,SetFood] = useState([])
    useEffect(()=>{
      (async() => {
        let { data } = await Getfood()
        SetFood(data)
      })()
    },[])

    return(
        <div>
        <Tabs defaultActiveKey='1' style={
          {'--title-font-size':'15px','--active-line-height':'0px',
          '--active-title-color':'#ed2b43'}}>
          <Tabs.Tab title='推荐' key='1'>
            {list.map(item=>(
              <Recommend source={item} key={item.id}/>
            ))
              }
          </Tabs.Tab>
          <Tabs.Tab title='视频' key='2'>
            <Video/>
          </Tabs.Tab>
          <Tabs.Tab title='直播' key='3'>
            <Liver />
          </Tabs.Tab>
          <Tabs.Tab title='美食' key='4'>
            {food.map(item=>(
              <Food entry={item} key={item.id}/>
            ))
              }
          </Tabs.Tab>
          <Tabs.Tab title='知识科普' key='5'>
           .........
          </Tabs.Tab>
           .........
            此后代码大致相同,便在此处省略
        </Tabs>
        <SpinLoading style={{'--color':'#ed2b43'}} className="load"/>     
        </div>
    )
 }

 export default Find

  본 프로젝트의 Tab bar는 antd-mobile에 패키징된 Tab bar를 사용하고 있으며, antd-mobile의 문서를 참고한 후 관련 컴포넌트를 소개하여 사용하시면 됩니다. 사용이 더 편리하지만 패키지 구성 요소이기 때문에 일부 스타일의 수정이 더 제한됩니다. 스타일을 수정하려면 문서를 참조하여 관련 스타일을 수정하거나 className 클래스 이름을 추가하여 관련 스타일을 재정의할 수 있습니다. 관련 웹사이트는 아래에 첨부되어 있습니다. 관심 있는 친구들은 관련 문서를 참조할 수 있습니다. 이것은 좋은 UI 컴포넌트 라이브러리입니다.
앤트 디자인 모바일 - 앤트 디자인 모바일

홈 콘텐츠

QQ录屏20220705164119.gif


  홈 페이지는 이 프로젝트의 메인 페이지이며, 이 페이지에 들어가면 페이지 점프와 같은 관련 기능을 구현할 수 있습니다. 페이지의 데이터는 fastmock에 저장됩니다. 그런 다음 Recommend 및 Food 페이지에서 순회하여 페이지에서 필요한 데이터를 얻습니다. 또한 검색 페이지로 이동하면 그 안에서 사용하는 검색창도 antd-mobile에 패키징된 Search 입니다.스타일을 약간 수정하여 직접 호출할 수 있습니다. 아이콘의 경우 iconfont의 아이콘을 사용하면 대부분의 요구 사항에 충분합니다. 자산 폴더에 미리 아이콘이 추가된 글꼴 폴더를 도입하면 글꼴 폴더에서 아이콘 스타일을 쉽게 수정할 수 있습니다. 소스 코드의 일부는 다음과 같습니다.

검색.jsx

import React from "react";
import { NavBar,SearchBar } from "antd-mobile";
import {Link} from "react-router-dom"
import './style.css'

 const Search = () =>{
    return(
        <div>
            <Link to='/shop'>
           <NavBar>
                <SearchBar 
                className="searchbar"
                placeholder='请输入内容'
                style={{
                    '--border-radius': '100px',
                    '--background': '#f5f5f5',
                    '--height': '30px',
                    '--placeholder-color':'#afafaf',    
                }}
                />
                <span className="search">搜索</span>
            </NavBar>
            </Link>
        </div>
    )
 }

 export default Search

추천.jsx

import React from "react";
import './style.css'

 const Recommend = ({source}) =>{
    const {img,content,author,icon} = source  
    return(
        <div className="List">
          <img src={img} className="list-img" />
          <div className="list-content">{content}</div>
          <div className="list-author">
            <img src={icon} className="icon-img"></img>
            <div className="list-h">{author}</div>
            <i className="iconfont icon-dianzan"></i>
          </div>
        </div>
    )
 }

 export default Recommend

Food.jsx

import React from "react";
import './style.css'

 const Food = ({entry}) =>{
    const {img,content,author,icon} = entry  
    return(
        <div className="List">
          <img src={img} className="list-img" />
          <div className="list-content">{content}</div>
          <div className="list-author">
            <img src={icon} className="icon-img"></img>
            <div className="list-h">{author}</div>
            <i className="iconfont icon-dianzan"></i>
          </div>
        </div>
    )
 }

 export default Food

요약하다

  이것은 예비 프로젝트로 아직 완전히 구현되지 않은 많은 기능과 관련 구성 요소가 있습니다.이 프로젝트는 나중에 깊이 연구하고 React 지식을 숙달하여 수정 및 개선되어 계속 게시됩니다. 최적화나 오류가 있는 경우 댓글 영역에 지적해 주시기 바랍니다. 마지막으로 이 글이 도움이 되셨다면 좋아요 눌러주시면 감사 하겠습니다 ღ( ´・ᴗ・` )

рекомендация

отjuejin.im/post/7116817540055040013