首先肯定是搭建项目的结构了,通过脚手架安装这部分我就不说了
首先看项目的目录结构
assets:放我们的静态资源,图片,字体和公共初始样式等
common:放我们公共的JS文件
components:放我们项目的公共组件
pages:放项目的主视图组件
router:放项目的路由配置
services:网络请求部分
store:放redux的相关配置
utils:放一些处理我们数据的JS方法
一.我们引入文件的时候经常就是这样
../../../../
感觉太邋遢了
安装一个插件吧
yarn add @craco/craco
然后在我们项目的根目录,也就是src的同级目录,建立一个craco.config.js
// 导入文件可以用@
const path = require("path");
const resolve = dir => path.resolve(__dirname, dir);
module.exports = {
webpack: {
alias: {
"@": resolve("src"),
"components": resolve("src/components")
}
}
}
然后在我们的package.json中,将scripts改成这样的
今后导入我们的任何文件直接这样写
import { } from '@/common';
import from '@/components';
二.先定义一些初始样式比较好,在入口index.js引入,项目主要是用styled-components写的
yarn add normalize.css
然后在assets中建立一个css文件,css文件里面建立一个reset.css
@import "~normalize.css";
/* 样式的重置 */
body, html, h1, h2, h3, h4, h5, h6, ul, ol, li, dl, dt, dd, header, menu, section, p, input, td, th, ins {
padding: 0;
margin: 0;
}
ul, ol, li {
list-style: none;
}
a {
text-decoration: none;
color: #666;
}
a:hover {
color: #666;
text-decoration: underline;
}
i, em {
font-style: normal;
}
input, textarea, button, select, a {
outline: none;
border: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
img {
border: none;
vertical-align: middle;
}
/* 全局样式 */
body, textarea, select, input, button {
font-size: 12px;
color: #333;
font-family: Arial, Helvetica, sans-serif;
background-color: #f5f5f5;
}
.text-nowrap {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.wrap-v1 {
width: 1100px;
margin: 0 auto;
}
.wrap-v2 {
width: 980px;
margin: 0 auto;
}
.sprite_01 {
background: url(../img/sprite_01.png) no-repeat 0 9999px;
}
.sprite_02 {
background: url(../img/sprite_02.png) no-repeat 0 9999px;
}
.sprite_covor {
background: url(../img/sprite_cover.png) no-repeat 0 9999px;
}
.sprite_icon {
background: url(../img/sprite_icon.png) no-repeat 0 9999px;
}
.sprite_icon2 {
background: url(../img/sprite_icon2.png) no-repeat 0 9999px;
}
.sprite_button {
background: url(../img/sprite_button.png) no-repeat 0 9999px;
}
.sprite_button2 {
background: url(../img/sprite_button2.png) no-repeat 0 9999px;
}
.sprite_table {
background: url(../img/sprite_table.png) no-repeat 0 9999px;
}
.image_cover {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
text-indent: -9999px;
background: url(../img/sprite_cover.png) no-repeat -145px -57px;
}
我先把这些样式写这了,因为网易云音乐,它里面很多的图片都用的是精灵图,我提前给他们把位置和样式确定了一下
三.先在pages里面建立三个视图文件,discover,friend,mine(其他几个是跳转外部链接的,不需要路由)
import React, { memo } from 'react';
export default memo(function LSHDiscover() {
return (
LSHDiscover
)
})
import React, { memo } from 'react';
export default memo(function LSHFriend() {
return (
HYFriend
)
})
import React, { memo } from 'react';
export default memo(function LSHMine() {
return (
LSHMine
)
})
然后discover有6个子路由,我就不一一写了
至于为什么用memo?节省性能
组件仅在它的 props 发生改变的时候进行重新渲染
四.配置路由
yarn add react-router-config
yarn add react-router-dom
在我们的router文件中建立一个index.js
import React from 'react'
import LSHDiscover from "@/pages/discover";
import HYRecommend from "@/pages/discover/c-pages/recommend";
import HYRanking from "@/pages/discover/c-pages/ranking";
import HYSongs from "@/pages/discover/c-pages/songs";
import HYDjradio from "@/pages/discover/c-pages/djradio";
import HYArtist from "@/pages/discover/c-pages/artist";
import HYAlbum from "@/pages/discover/c-pages/album";
import LSHMine from "@/pages/mine";
import LSHFriend from "@/pages/friend";
import {Redirect} from 'react-router-dom'
Redirect是为了重定向,当进页面的时候展示哪一个
下面是routes
const routes = [
{
path: "/",
exact:true,
render:()=>(
)
},
{
path: "/discover",
component: LSHDiscover,
routes: [
{
path: "/discover",
exact: true,
render: () => (
)
},
{
path: "/discover/recommend",
component: HYRecommend
},
{
path: "/discover/ranking",
component: HYRanking
},
{
path: "/discover/songs",
component: HYSongs
},
{
path: "/discover/djradio",
exact: true,
component: HYDjradio
},
{
path: "/discover/artist",
component: HYArtist
},
{
path: "/discover/album",
component: HYAlbum
}
]
},
{
path: "/mine",
component: LSHMine
},
{
path: "/friend",
component: LSHFriend
},
];
同时别忘了导出
export default routes
五.在APP.js中配置
import React, { memo } from 'react'
import {renderRoutes} from 'react-router-config'
import { HashRouter } from 'react-router-dom';
import routes from './router'
import LSHAppHeader from '@/components/app-header'
export default memo(function App() {
return (
{renderRoutes(routes)}
)
})
在这里我们用的是hash路由,LSHAppHeader是我们下面这个,下面开始写
六.开始app-header组件的编写
在components中创建一个app-header文件,里面建立一个index.js和style.js
由于我们这个东西用到了antd这个ui库,先安装一下,别忘了导入样式,可以在我们定义的reset.css中导入
@import "~antd/dist/antd.css";
安装antd
yarn add antd
yarn add @ant-design/icons
index.js
import React, { memo } from 'react';
import { headerLinks } from '@/common/local-data'
import { NavLink } from 'react-router-dom';
import { SearchOutlined } from '@ant-design/icons'
import { Input } from 'antd'
import {
HeaderWrapper,
HeaderLeft,
HeaderRight
} from './style'
export default memo(function LSHAppHeader() {
//业务代码
const showSelectItem = (item, index) => {
if (index < 3) {
return (
{item.title}
)
} else {
return {item.title}
}
}
//返回到jsx
return (
网易云音乐
{
headerLinks.map((item, index) => {
return (
{showSelectItem(item, index)}
)
})
}
} />
创作者中心
登录
)
})
headerLinks是我们一些公共js数据,在common中创建一个local-data.js
export const headerLinks = [
{
title: "发现音乐",
link: "/discover"
},
{
title: "我的音乐",
link: "/mine"
},
{
title: "朋友",
link: "/friend"
},
{
title: "商城",
link: "https://music.163.com/store/product"
},
{
title: "音乐人",
link: "https://music.163.com/nmusician/web/index#/"
},
{
title: "下载客户端",
link: "https://music.163.com/#/download"
}
]
style.js样式为,要先安装我们的styled-components,yarn add styled-components
import styled from "styled-components";
export const HeaderWrapper = styled.div`
height: 75px;
font-size: 14px;
color: #fff;
background-color: #242424;
.content {
height: 70px;
display: flex;
justify-content: space-between;
}
.divider {
height: 5px;
background-color: #C20C0C;
}
`
export const HeaderLeft = styled.div`
display: flex;
.logo {
display: block;
width: 176px;
height: 69px;
background-position: 0 0;
text-indent: -9999px;
}
.select-list {
display: flex;
line-height: 70px;
.select-item {
position: relative;
a {
display: block;
padding: 0 20px;
color: #ccc;
}
:last-of-type a {
position: relative;
::after {
position: absolute;
content: "";
width: 28px;
height: 19px;
background-image: url(${require("@/assets/img/sprite_01.png")});
background-position: -190px 0;
top: 20px;
right: -15px;
}
}
&:hover a, a.active {
color: #fff;
background: #000;
text-decoration: none;
}
.active .icon {
position: absolute;
display: inline-block;
width: 12px;
height: 7px;
bottom: -1px;
left: 50%;
transform: translate(-50%, 0);
background-position: -226px 0;
}
}
}
`
export const HeaderRight = styled.div`
display: flex;
align-items: center;
color: #ccc;
font-size: 12px;
.search {
width: 158px;
height: 32px;
border-radius: 16px;
input {
&::placeholder {
font-size: 12px;
}
}
}
.center {
width: 90px;
height: 32px;
line-height: 32px;
text-align: center;
border: 1px solid #666;
border-radius: 16px;
margin: 0 16px;
background-color: transparent;
}
`
好了,最顶部的完成了
下面写这个discover的子路由视图
我们去到discover这个文件的index.js中
import React, { memo } from 'react';
//子路由渲染
import { renderRoutes } from 'react-router-config';
import { dicoverMenu } from "@/common/local-data";
import { NavLink } from 'react-router-dom';
import {
DiscoverWrapper,
TopMenu
} from './style';
export default memo(function LSHDiscover(props) {
// 子路由渲染
const { route } = props;
return (
{
dicoverMenu.map((item, index) => {
return (
{item.title}
)
})
}
{renderRoutes(route.routes)}
)
})
dicoverMenu这个文件的东西
export const dicoverMenu = [
{
title: "推荐",
link: "/discover/recommend"
},
{
title: "排行榜",
link: "/discover/ranking"
},
{
title: "歌单",
link: "/discover/songs"
},
{
title: "主播电台",
link: "/discover/djradio"
},
{
title: "歌手",
link: "/discover/artist"
},
{
title: "新碟上架",
link: "/discover/album"
},
]
style.js
import styled from 'styled-components';
export const DiscoverWrapper = styled.div`
.top {
height: 30px;
background-color: #C20C0C;
}
`
export const TopMenu = styled.div`
display: flex;
padding-left: 180px;
position: relative;
top: -4px;
.item {
a {
display: inline-block;
height: 20px;
line-height: 20px;
padding: 0 13px;
margin: 7px 17px 0;
color: #fff;
&:hover, &.active {
text-decoration: none;
background-color: #9B0909;
border-radius: 20px;
}
}
}
`
好了,这个页面基本就完成了,下一篇博客就要通过网络请求获取数据到我们redux中存储了,这两个页面