项目准备
该项目为一个由react开发的仿抖音的短视频网站,具体将实现以下几个目标和功能:
1.实现类似的css布局和样式
2.实现上下滑动切换区域的功能
3.自定义一个视频播放器。
4.实现上下滑动切换视频和播放的功能
5.实现视频点赞的功能
项目初始化
一.安装Node.js
本人使用的是mac系统以下为安装node.js的两种方式:
第一种是在官方网站 (nodejs.org/en/download) 中找到安装包下载后安装,安装完成后在终端输入node -v。如果终端输出了Node.js的版本号,那么表示安装成功。
我所采用的是第二种:安装nvm,用nvm安装node.js。先安装Homebrew,命令行输入brew install nvm安装nvm,安装完成后开始配置nvm环境变量,打开.zshrc文件,如果没有该文件,可以使用文本编辑器创建一个。在.zshrc文件的末尾添加以下行
export NVM_DIR="$HOME/.nvm"
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" # This loads nvm
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion
在终端中运行source ~/.zshrc
命令,使.zshrc文件中的更改生效。
然后在终端中输入nvm -v,如果显示nvm的版本号,则表示安装成功;最后你可以使用 nvm install <version> 命令来安装指定版本的Node.js,其中 <version> 是你想要安装的Node.js版本号。
二.创建react项目
这里选择Modern.js作为开发框架。在完成环境的准备后,在终端中依次输入以下命令创建新目录和初始化项目。
mkdir shortvideo && cd shortvideo
npx @modern-js/create@latest
@modern-js/create 会提供一个可交互的问答界面,根据需要选择初始化
? 请选择你想创建的工程类型 Web 应用
? 请选择开发语言 ES6+
? 请选择包管理工具 npm
? 请选择构建工具 webpack
在初始化后项目的目录结构大致如下
在终端中输入 npm run dev 启动项目。
在浏览器中打开 http://localhost:8000/,看到内容后表示项目启动成功。
项目启动成功之后开始删除不必要的文件,准备编辑项目。
实现整体css布局
观察抖音网页版,得出网页的大致css布局:由左右两边大区域构成,右边区域由顶部导航栏和底部的视频两大区域构成。
左右两部分可由flex布局实现,顶部导航栏的搜索栏、用户栏、和登陆栏也可由flex实现。
分别创建main.jsx aside.jsx top.jsx style.css四个文件
一.完成aside.jsx文件内容
这部分为左侧侧边栏的内容,大致分为上中下三个部分
function Asidearea() {
return (
<div className="asidecontainer">
{/* 头部logo部分 */}
<div className="alogo-p">
<div className="alogoarea">
<div className="alogo"></div>
</div>
</div>
<div className="roll-p">
{/* 中间选项部分以首页选项为例 */}
<div className="rollarea">
<div className="rollitems">
<div
className="rollitems-icon"
style={{ backgroundPosition: '0px 0px', backgroundSize: '864px' }}
></div>
<div className="rollitemstext-p">
<span className="rollitemstext">首页</span>
</div>
</div>
</div>
{/* 省略了其他选项 */}
<div className="divisionline"></div>
{/* 底部选项部分 */}
<div className="fixedarea">
<div className="fixeditems"></div>
</div>
</div>
);
}
export default Asidearea;
在style.css中完成一下样式
.asidecontainer {
width: 160px;
height: 554px;
}
.alogo-p {
position: relative;
height: 68px;
width: 160px;
}
.alogoarea {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 112.195px;
width: 160px;
}
.alogo {
background-image: url('https://lf3-cdn-tos.bytegoofy.com/obj/goofy/ies/douyin_web/media/logo-horizont-dark.68c22817059ee9a7.svg');
background-repeat: no-repeat;
width: 91px;
height: 28px;
}
.roll-p {
height: 100%;
width: 100%;
flex-direction: column;
flex-grow: 1;
padding-bottom: 0;
overflow: hidden;
}
.rollarea {
display: flex;
flex-direction: row;
align-items: flex-end;
height: 40px;
width: 128px;
margin: 2px 16px 0;
}
.rollitems {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
width: 128px;
height: 24px;
padding: 8px 16px;
}
.rollitems-icon {
background-image: url('https://lf3-cdn-tos.bytegoofy.com/obj/goofy/ies/douyin_web/media/nav_dark_entry_optimize.2a3902ccbc541c43.png');
width: 24px;
height: 24px;
margin-right: 12px;
}
.rollitemstext {
font-size: 14px;
line-height: 24px;
font-weight: 500;
margin-top: -4px;
color: rgba(255, 255, 255, 0.6);
}
.divisionline {
height: 1px;
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
margin: 12px 24px 10px;
}
二.完成top.jsx文件中的内容
function Toparea() {
return (
<div className="topcontainer-p">
<div className="topcontainer">
<div className="topcontainer-bar">
<div className="searcharea">
<div className="search">
<div className="search-inside">
<input className="search-input" type="text" />
</div>
<button className="search-button">
<svg
width="18"
height="18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="tO5FPupE"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.875 1.5a6.375 6.375 0 103.642 11.608l3.063 3.063a1.125 1.125 0 001.59-1.591l-3.062-3.063A6.375 6.375 0 007.875 1.5zM3.75 7.875a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0z"
fill="#fff"
></path>
</svg>
<span className="btn-title">搜索</span>
</button>
</div>
</div>
<div className="tothersarea">
<div className="tothers">
<div className="tothers-items">
<div className="tothers-icons">
<div className="tothers-svg">
<svg
width="24"
height="24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="xhLouUc0"
viewBox="0 0 24 24"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.757 12.268a6.397 6.397 0 1112.793 0 6.397 6.397 0 01-12.793 0zm6.396-7.897a7.897 7.897 0 100 15.793 7.897 7.897 0 000-15.793zm2.127 3.52v-.497h-1.5v6.462h.001c0 .854-.685 1.536-1.517 1.536a1.527 1.527 0 01-1.517-1.536c0-.854.685-1.536 1.517-1.536v-1.5c-1.672 0-3.017 1.365-3.017 3.036 0 1.67 1.345 3.036 3.017 3.036s3.017-1.365 3.017-3.036h-.001v-3.228a3.184 3.184 0 001.715.498v-1.5a1.725 1.725 0 01-1.715-1.735z"
fill="rgba(255, 255, 255, 0.6)"
></path>
</svg>
</div>
<div className="tothers-text">充钻石</div>
</div>
</div>
</div>
<div className="signin"></div>
</div>
<div>
<div className="signinarea">
<button className="signin-btn">
<svg
width="18"
height="18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className=""
viewBox="0 0 18 18"
id="svg_icon_avatar"
>
<rect
width="18"
height="18"
rx="9"
fill="#fff"
fillOpacity="0.3"
></rect>
<path
d="M2.244 14.946A8.978 8.978 0 019 11.893a8.978 8.978 0 016.756 3.053A8.978 8.978 0 019 18a8.978 8.978 0 01-6.756-3.054zM12.214 7.393a3.214 3.214 0 11-6.428 0 3.214 3.214 0 016.428 0z"
fill="#fff"
></path>
</svg>
{/* 省略了其他选项 */}
<p className="signin-text">登录</p>
</button>
</div>
</div>
</div>
</div>
</div>
);
}
export default Toparea;
在style.css文件中添加代码
.topcontainer-p {
height: 68px;
justify-content: space-between;
align-items: center;
display: flex;
position: relative;
}
.topcontainer {
display: flex;
align-items: center;
width: 100%;
height: 100%;
margin: 0;
margin-right: 16px;
padding-left: 0;
}
.topcontainer-bar {
display: flex;
justify-content: flex-end;
align-items: center;
position: relative;
width: 100%;
height: 100%;
box-sizing: border-box;
flex-direction: row;
flex-grow: 1;
padding-right: 0 !important;
}
.searcharea {
display: flex;
align-items: center;
position: absolute;
left: 343.719px;
right: 400px;
width: 360.281px;
height: 68px;
padding: 0;
}
.search {
display: flex;
align-items: center;
border: 2px solid rgba(255, 255, 255, 0.7);
border-radius: 12px;
background-color: transparent !important;
width: 360.281px;
box-sizing: border-box;
height: 40px;
flex-direction: row;
}
.search-inside {
height: 100%;
z-index: 50;
flex: 1;
align-items: center;
display: flex;
position: relative;
overflow: hidden;
}
.search-input {
color: rgba(255, 255, 255, 0.75);
background: 0 0;
border-top-left-radius: 12px !important;
border-bottom-left-radius: 12px !important;
padding: 0 12px;
font-size: 14px;
font-weight: 400;
line-height: 22px;
border: none;
outline: none;
flex-grow: 1;
margin: 0;
z-index: 100;
height: 100%;
}
.search-button {
display: flex;
justify-content: center;
align-items: center;
width: 69px;
height: 36px;
cursor: pointer;
z-index: 50;
border: none;
background: 0 0;
border-top-right-radius: 12px !important;
border-bottom-right-radius: 12px !important;
}
.btn-title {
color: #fff;
font-size: 16px;
font-weight: 500;
line-height: 24px;
margin-left: 3px;
}
.tothersarea {
display: flex;
justify-content: flex-end;
align-items: center;
height: 44px;
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
.tothers {
display: flex;
justify-content: center;
align-items: center;
margin-left: 8px;
}
.tothers-items {
width: auto;
height: 44px;
min-width: 32px;
flex-direction: column;
align-items: center;
display: inline-flex;
position: relative;
}
.tothers-icons {
display: flex;
cursor: pointer;
flex-direction: column;
align-items: center;
width: 30px;
height: 44px;
}
.tothers-svg {
display: flex;
justify-content: center;
align-items: center;
width: 24px;
height: 24px;
border-radius: 72px;
background: 0 0 !important;
}
.tothers-text {
word-break: keep-all;
text-align: center;
font-size: 10px;
font-weight: 500;
line-height: 20px;
color: rgba(255, 255, 255, 0.6);
}
.signinarea {
list-style-type: none;
position: relative;
z-index: 99;
margin-left: 16px;
}
.signin-btn {
width: 88px;
height: 38px;
border-radius: 12px;
padding: 6px 16px;
align-items: center;
margin: 0;
font-size: 15px;
line-height: 23px;
display: flex;
border: 1px solid rgb(254, 44, 85);
background-color: rgb(254, 44, 85);
color: #fff;
font-weight: 500;
min-width: 88px;
}
.signin-text {
margin-left: 4px;
}
初步的布局样式
在page.jsx中引入style.css和各部分文件
import './style.css';
import Toparea from './top';
import Asidearea from './aside';
import Mainarea from './main';
function App() {
return (
<div className="container">
<Asidearea />
<div className="content">
<Toparea />
<Mainarea />
</div>
</div>
);
}
export default App;
最终呈现出效果大致为这样