从零开始搭建React开发项目之抖音“剪映”——创作课堂(基础入门篇)

本文从零开始教你如何使用React和相关依赖搭建一个仿抖音'剪映'的前端项目,包括项目初始化、组件设计、路由配置、页面详细设计等步骤,适合React初学者。

前言

React是近几年来前端项目开发非常火的一个框架,其背景是Facebook团队的技术支持,市场占有率也很高,对于很多新手来说可能很多人都在犹豫是选react还是vue,如果时间充裕的话还是首选react(虽然有一点难),但不得不说React无论从性能上还是思想上(组件化)都比vue更为先进。下面我带来的react组件化设计希望能够帮助到一些和我一样刚学习react的新手

组件展示

  • 剪映原版
  • 仿剪映盗版

项目搭建与安装依赖

1.项目初始化 npm init @vitejs/app 选择react (这里我使用的是vite搭建项目,如果大家用其他的更顺手也可以用其他的)
2.安装相关依赖 npm react-router react-router-dom
3.其他相关依赖* npm i axios 使用ajax请求服务端接口(这里我使用的是fastmock www.fastmock.site/#/  在线模拟ajax请求)* npm i classnames 用来合并类名的,存在多个类名变量时,想添加到对应的元素中* npm i styled-components 使用atyled-components设置页面样式* npm i swiper 使用swiper轮播图 注意下载的版本是4.5.0的(这里我先前安装的是最新版本的不会用导致轮播图轮播根本动不了)
4.创建文件夹* 根目录 public 静态资源目录 不需要在src 里面引入* src下* api 封装axios接口* assets 放置静态资源 如图片/字体图标/全局样式* components 放置通用组件* pages 单页面存放* routers 独立配置文件 把组件封装到一起

5.启动项目 npm run dev 默认在3000端口
6.初始化设置* 不同型号手机端适应页面* 在public文件夹下创建js子文件夹创建adapter.js文件这里设置20px为1rem 后面所有的大小将不再使用px,使用rem代替px确保能够适应所有的手机型号var init = function () {var clientWidth = document.documentElement.clientWidth || document.body.clientWidth;if (clientWidth >= 640) {clientWidth = 640;}var fontSize = 20 / 375 * clientWidth;document.documentElement.style.fontSize = fontSize + "px";}init();window.addEventListener("resize", init);``````* 下载相应的图标、图片和对样式reset* 在assets 下创建font、image和styles文件夹* 字体图标就在iconfont上去下载自己想要的或者使用font-awesome组件库* image 可以下载需要的图标或者等会在fastmock传入数据(可要可不要)* reset 就是对页面进行样式重置(这里代码太长,推荐随便到掘金或者github上找一个比较全的样式重置就好了)* 导入数据* api文件夹下创建request.js文件 封装axios 首先在fastmock上创建好数据(这里是我的fastmock地址)import axios from 'axios’export const getCourse=()=>axios.get(‘https://www.fastmock.site/mock/758a51ea7ac094acd3f3de097e2da039/beers/course’) ```

页面设计思路

  • 页面级别组件 <Home/> 他是其他页面的父组件* <Header/> 头部组件每个页面都需要使用* <Footer/> 尾部组件tabbar 可以切换页面* <HomeDetailNav/> 由这个组件切换到二级页面
  • 精品课二级页面* <Banner/> 录播图组件* <Lists /> 列表展示组件* <Course/> 课程展示页面

项目页面详细设计

路由配置

这个项目的路由配置有点多,会用到二级路由,所以我们将所有的路由单独封装到routers文件夹下 这里使用lazy懒加载,提升主页打开的速度

我主要写的是Home和Jingpin组件,其他页面主要是占位,在后续会完成其他页面的制作

import { useState, lazy } from 'react'
import { Routes, Route, Link} from 'react-router-dom'
import Home from '../pages/Home'
const Course = lazy(() => import('../pages/Course'))
const Jianji = lazy(() => import('../pages/JianJi'))
const Mine = lazy(() => import('../pages/Mine'))
const News = lazy(() => import('../pages/News'))
const TongKuan = lazy(() => import('../pages/Tongkuan'))
const Jianpai = lazy(() => import('../pages/Jianpai'))
const Mianfei = lazy(() => import('../pages/Mianfei'))
const Tuijian = lazy(() => import('../pages/Tuijian'))
const Zhibo = lazy(() => import('../pages/Zhibo'))
const Jingpin = lazy(() => import('../pages/Jingpin'))

// Routes 不能和react-router-dom 一样
const RoutesConfig = () => {return (<Routes><Route path='/' element={<Home/>}><Route path='/' element={<Jingpin/>}/></Route><Route path='/jianji' element={<Jianji/>}></Route><Route path='/tongkuan' element={<TongKuan/>}></Route><Route path='/home' element={<Home/>}>{/* 二级路由 */}<Route path='/home/tuijian' element={<Tuijian/>}/><Route path='/home/mianfei' element={<Mianfei/>}/><Route path='/home/jingpin' element={<Jingpin/>}/><Route path='/home/' element={<Jingpin/>}/><Route path='/home/zhibo' element={<Zhibo/>}></Route><Route path='/home/jianpai' element={<Jianpai/>}/></Route><Route path='/news' element={<News/>}></Route><Route path='/mine' element={<Mine/>}></Route><Route path='/course/:id' element={<Course/>}></Route></Routes>)
}

export default RoutesConfig 

App.jsx

在App.jsx中代码很简单,由Header组件和Footer组件 还有页面二级路由组件构成

这里使用Suspense 等待异步组件时渲染一些额外内容,让应用有更好的用户体验,在页面还没有加载出来时提示loading加载中

import { useState,Suspense } from 'react'
import './App.css'
import RoutesConfig from './routers'
import Header from './components/Header'
import Footer from './components/Footer'

function App() {return (<div className="App"><Header /><Suspense fallback={<div>loading...</div>}><RoutesConfig /></Suspense><Footer /></div>)
}

export default App 

Header组件展示

  • 头部做的是一个输入框和一个div盒子放置,引入了字体图标iconfont,这里只是简单的切页面,具体样式就不展示了
 <Header><div className="inphead"><i className='iconfont icon-sousuo sousuo'></i><input type="text" placeholder='好友组团卡点照' className='inp' /><div className='stu'><i className='iconfont icon-24gl-playSquare'></i><p>学习中心</p></div></div> </Header> 

Footer组件展示

  • 这里使用路由NavLink实现对页面的跳转 当跳转到当前底部图标和文字时会高亮显示
export default function Footer() {const {pathname}=useLocation()return (<FooterWrapper><NavLink to="/jianji" className={classnames({active:pathname=='/jianji'})}><i className='iconfont icon-jianji'></i><span>剪辑</span></NavLink><NavLink to="/tongkuan" className={classnames({active:pathname=='/tongkuan'})}><i className='iconfont icon-shipin'></i><span>剪同款</span></NavLink><NavLink to="/home" className={classnames({active:pathname=='/home' || pathname=='/'})}><i className='iconfont icon-wodekecheng'></i><span>创作课堂</span></NavLink><NavLink to="/news" className={classnames({active:pathname=='/news'})}><i className='iconfont icon-xiaoxi'></i><span>消息</span></NavLink><NavLink to="/mine" className={classnames({active:pathname=='/mine'})}><i className='iconfont icon-31wode'></i><span>我的</span></NavLink></FooterWrapper>)
} 

二级路由

<Home/>组件中引入<HomeDetailNav/>二级组件和使用<Outlet />对下面的组件进行占位 下面主要介绍<HomeDetailNav/>组件

export default function HomeDetailNav(){let homeNavs = [{ id: 1, desc: '推荐', path: '/tuijian'},{ id: 2, desc: '免费专区', path: '/mianfei'},{ id: 3, desc: '精品课', path: '/jingpin'},{ id: 4, desc: '直播', path: '/zhibo'},{ id: 5, desc: '拍剪教学', path: '/jianpai'},]return(<Wrapper ><div className="navbar swiper-container"><div className="nav-box swiper-wrapper">{homeNavs.map((item, index) => {return (<NavLinkindex={index}to={`/home${item.path}`}key={item.id}className="nav-item swiper-slide">{item.desc}</NavLink>)})}</div></div></Wrapper>)
} 

这里使用map循环输出二级路由的地址 点击不同的文字可以到不同的页面 且路由有高亮显示

精品课页面组件介绍

轮播图设计

<Banner/>组件这里使用swiper组件库对轮播图进行设置 使用useEffect钩子对轮播图进行渲染,轮播图设置3秒自动轮播

 export default function Banner() {useEffect(() => {new Swiper('.home_info_banner',{loop:true,autoplay: {delay:3000}})},[])
return (<Wrapper><div className="home_info_img"><div className="home_info_banner swiper-container"><div className="swiper-wrapper"><div className="swiper-slide"><img src={img1} alt="" width="100%" /></div><div className="swiper-slide"><img src={img2} alt="" width="100%" /> </div></div><div className="swiper-pagination"></div></div></div></Wrapper>
)
} 
列表展示

<Lists/> 这个组件很简单就是使用一级路由直接跳转

<Link to="/kecheng"><i className='iconfont icon-wodekecheng'></i><span>全部课程</span>
</Link>
... 
课程组件

<Course/> 课程组件 负责课程的展示 这里由fastmock传入数据

布局使用弹性布局加absolute定位

<Wrapper>{/* <h1>超值限时抢</h1> */}{course&&course.map(item=>(<div className="course-flex"><LinkclassName='course-List'to={`/course/${item.id}`}key={item.id}><div className="course-Box"><div className="course-Img"><img src={item.img} alt="" /><div className="get-Course"><p>{item.coursenum}节课</p></div></div><div className="course-Content"><div className="course_header">{item.header}</div><div className="course_name"><span>{item.name}</span> <p>|</p><span>{item.people}</span></div><div className="course_price"><span className='course_price_now'><p>¥</p>{item.price}</span><span className='course_price_old'><p>¥</p>{item.low_price}</span></div></div></div></Link></div>))}</Wrapper> 

这里我没找到合适的图片就都用了相同的图片,后续如果找到了会修改的

最后

项目待改进地方

这个组件我做的比较简单,就是简单的切页面和路由转换,还有很多地方还没有做出来,后续会继续更新,完成这个项目,请持续关注

后续项目待完善地方

1.完善换一换,可以切换到下一页
2.点进课程可以看到课程内容
3.再写几个页面

项目地址

gitee.com/boluotou12/…

gitee.com/boluotou12/…](https://link.juejin.cn/?target=https%3A%2F%2Fgitee.com%2Fboluotou12%2Freact-jianying%2Ftree%2Fmaster “https://gitee.com/boluotou12/react-jianying/tree/master”)

感谢看到最后,如果觉得文章还不错的话点个赞再走吧 ()

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值