머리말
리액트 소개
React 는 주로 UI 구축을 위한 사용자 인터페이스 구축을 위한 JavaScript 라이브러리입니다. React는 JSX(JavaScript의 확장) 및 구성 요소와 같은 고성능 및 기능을 가지고 있습니다. 컴포넌트화의 개념은 React에서 널리 사용되며, 컴포넌트를 구성하여 코드를 잘 재사용할 수 있습니다. 또한 React 의 선언적 디자인과 DOM 에뮬레이션으로 인해 효율적이고 유연합니다.
프로젝트 설명
소셜 및 전자 상거래 에 위치하는 앱으로서 Xiaohongshu 는 최근 몇 년 동안 점점 더 많은 관심을 받고 있으며 사용자 기반도 확대되고 있습니다. Xiaohongshu의 사용자로서 최근 React에 대한 지식과 결합하여 Xiaohongshu 의 홈페이지를 모방하기 위해 React 를 사용할 생각이 있습니다. 이 프로젝트는 Xiaohongshu 홈페이지의 기본 페이지를 구현하고 프로젝트 디스플레이 및 실제 전투로 이동합니다.
완제품 전시
여기 이미지가 있습니다
실수했어, 돌아와
프로젝트 전투
첫 단계
Vscode에서 React 프로젝트 만들기 프로젝트 를 만드는 방법에는 여러 가지가 있습니다. 공식 스캐폴딩 create-react-app 또는 Webpack을 사용하여 생성합니다. 여기서는 Vitejs 방법을 사용하여 다른 방법보다 훨씬 빠르게 만듭니다. 이에 관심이 있으시면 나중에 Vite와 Webpack에 대한 글을 작성 하겠습니다 .
폴더 구성
프로젝트가 생성되면 다음 단계는 관련 파일 및 관련 중복 파일의 코드를 정리하고 프로젝트에서 가장 기본적인 폴더를 생성하는 것입니다.
- 네트워크 요청을 위한 api 폴더
- 자산 폴더는 아이콘 및 그림과 같은 일부 정적 리소스를 저장하는 데 사용됩니다.
- 페이지용 페이지 폴더
- 재사용 가능한 구성 요소를 위한 compmtents 폴더
자세한 파일 디렉토리는 다음과 같습니다.
종속성 설치
相关文件夹配置完成后,可以开始安装项目需要的依赖
- 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 用于添加多个类名
安装成功后如下所示:
组件及页面分析
路由介绍
在以上工作完成后,接下来就是搭建相关路由了,路由在项目中是十分重要的。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}
- 若出现某个页面跳转后不显示底部导航栏,可以通过简单的条件判断和
{useLocation}
接受传来的值来实现。比如如下所示:
import {useLocation} from 'react-router-dom'
const {pathname}=useLocation()
if (pathname == '/choose') return
数据请求
在此项目中采用的是fastmock来请求与管理数据,然后在api文件夹中创建request.js来获取数据。后续在相关页面中引入即可。
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')
底部导航栏
底部导航栏通过路由的切换来实现。上面已经讲过一些路由知识,在此就不做过多描述。在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 />
</>
顶部导航栏
상단 탐색 모음은 탭 모음을 사용하여 콘텐츠를 전환합니다. 여기에 두 개의 탐색 모음이 있으며 검색 페이지 아래에도 탐색 모음이 있으므로 탐색 모음 효과를 두 번 구현해야 합니다. 두 탐색 모음의 구현은 매우 간단하며 소스 코드는 다음과 같습니다.
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 컴포넌트 라이브러리입니다.
앤트 디자인 모바일 - 앤트 디자인 모바일
홈 콘텐츠
홈 페이지는 이 프로젝트의 메인 페이지이며, 이 페이지에 들어가면 페이지 점프와 같은 관련 기능을 구현할 수 있습니다. 페이지의 데이터는 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 지식을 숙달하여 수정 및 개선되어 계속 게시됩니다. 최적화나 오류가 있는 경우 댓글 영역에 지적해 주시기 바랍니다. 마지막으로 이 글이 도움이 되셨다면 좋아요 눌러주시면 감사 하겠습니다 ღ( ´・ᴗ・` )