在react中实现一个仿抖音pc版应用(一)——项目初始化和实现整体css布局

977 阅读6分钟

项目准备

该项目为一个由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

在初始化后项目的目录结构大致如下

截屏2024-05-06 下午8.36.08.png

在终端中输入 npm run dev 启动项目。 在浏览器中打开 http://localhost:8000/,看到内容后表示项目启动成功。 项目启动成功之后开始删除不必要的文件,准备编辑项目。

实现整体css布局

观察抖音网页版,得出网页的大致css布局:由左右两边大区域构成,右边区域由顶部导航栏和底部的视频两大区域构成。
左右两部分可由flex布局实现,顶部导航栏的搜索栏、用户栏、和登陆栏也可由flex实现。 截屏2024-05-06 下午9.02.29.png 分别创建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;

最终呈现出效果大致为这样

截屏2024-05-07 下午7.47.52.png