准备工作
1. 使用create-react-app创建项目
- Create React App是FaceBook的React团队官方出的一个构建React单页面应用的脚手架工具。
- 它本身集成了Webpack,并配置了一系列内置的loader和默认的npm的脚本,可以很轻松的实现零配置就可以快速开发React的应用。
yarn global add create-react-app@3.4.1 (亦可用 npm 全局安装)
create-react-app morney --template typescript(项目名可以自定)
2. 添加.env文件
- 每次yarn start时会自动打开一个新的页面。设置为none,则不打开新界面。
BROWSER = none
3.设置git忽略.idea
git : 忽略.idea
git rm -r --cached .idea
4.目录解构说明
tsx和ts的区别
- .js和.jsx
- .js正常的js
- .jsx支持标签的js
- .ts和.tsx
- .ts正常ts
- .tsx支持标签的ts
对比vue和react的目录
- react更简洁
- create-react-app生成的几乎只有一个src和一个public
- 内置功能更少
- 没有自带router
- 没有自带redux
- 没有自带scss
5. StrictMode
StrictMode检查有没有用错的地方,纠正代码标签使用是否正确。
<React.StrictMode>
<App />
</React.StrictMode>,
6. css相关配置
css normalize
- 在index.css添加
@import-normalize; /* bring in normalize.css styles */
- 作用:保证页面在不同浏览器上默认样式相近
- IED不认识这个语法会报错,忽略即可。
- 个人认为这个东西没什么用,默认样式会被覆盖。
- 文档介绍
- css normalise和cssrest区别
scss
- 文档介绍
- 使用dart-sass代替node-sass
- node-scss: 下载失败:
- 1.可能下载不成功
-
- 本地编译比减慢
- react dart-scss会报错,使用
yarn add --dev node-sass@npm:dart-sass@1.25.0
表示在本地安装node-sass,但实际上用dart-sass
- 然后将所有.css改为.scss
- webstorm提示:选no
Enable File Watcher to compile SCSS to CSS? 6. 开发遇到问题:在react里支持sass
- 开始想让React支持saaa
- 需要node-sass,但是他有两个问题:下载速度慢,编译慢
- 于是想用dart-sass代替node-sass
- 但是react只支持node-sass,不支持dart-sass
- 通过我女里探索和查找
- 发现npm6.9的一个新功能,叫做package alias
- yarn add --dev node-sass@npm:dart-sass@1.25.0,在本地安装node-sass,但实际上用dart-sass
- 最终成功安上了dart-sass
- node-sass和dart-sass对比
- 链接
- 相同:都是用来将sass编译成css的工具。
- 区别:
- node-sass 是用 node(调用 cpp 编写的 libsass)来编译 sass;
- dart-sass 是用 drat VM 来编译 sass;
- node-sass是自动编译实时的,dart-sass需要保存后才会生效
- 推荐 dart-sass 性能更好(也是 sass 官方使用的),而且 node-sass 因为国情问题经常装不上
css的import引用更方便
- vue里面,使用@表示src/目录
- react不同
- 不需要@
- 可以使用@import 'xxx/yyy'来引入src/xxx/yyy.scss
- 配置文档
- JS也不需要@
- 在tsconfig.json添加一行
"baseUrl":"src"
- 为了配置方便,创建helper.scss
- 里面防止变量,函数等共用的东西
- 比如
$red:#f00
- index.scss里引用helper
@import 'helper'
7. css-in-js的方案:styled-component
css就在js里面,github
- 安装
yarn add styled-components
yarn add --dev @types/styled-components
- 不是重新写样式,而是让标签自带样式
import React from 'react';
import './App.css';
import styled from "styled-components";
const Button = styled.button`
color:red;
`;
function App() {
return (
<div>
<Button>hemm</Button>
</div>
);
}
export default App;
- 这样不用添加className,就可以添加样式了
- 如果button是通用的,可以把button单独保存一个文件
import styled from "styled-components";
const Button = styled.button`
color:red;
background: green;
`;
export default Button
- app.tsx
import React from 'react';
import './App.css';
import Button from "./components/Button";
import Box from "./components/Box";
function App() {
return (
<Box>
<Button>hemm</Button>
</Box>
);
}
export default App;
- 就是把css翻译为style标签
8. 配置总结
- 使用ts开发react
- 配置tsconfig.json后,可以使用import 'xxx' 以引用src/xxx
- css方面
- 使用dart-sass编译scss至css
- 直接import 'xxx' 引入src/xxx
- 变量和函数放入src/helper.scss
- 使用styled-components这种css-in-js的方案写css
开始制作
1. 制作底部导航
- 安装react-router
yarn add react-router-dom
yarn add --dev @types/react-router-dom
- 默认进入哪个页面
<Redirect exact from='/' to='/money'></Redirect>
- 如果不小心输入错误地址
<Route path="*">
<NoMatch />
</Route>
function NoMatch(){
return (
<div>
页面不存在
</div>
)
}
- switch切换
<Router>
<Switch >
<Route path="/tags">
<Tags />
</Route>
<Route path="/money">
<Money />
</Route>
<Route path="/statistics">
<Statistics />
</Route>
<Redirect exact from='/' to='/money'></Redirect>
<Route path="*">
<NoMatch />
</Route>
</Switch>
</Router>
- router 有2种模式
- history模式
- 切换hash
import { HashRouter as Router} from "react-router-dom";
2. 导航栏的定位
- fixed定位会有bug,能用就不用,手机上会有问题
- 用flex,弹性布局
- 夸平台中文字体css解决方案
- 封装:Nav单独放入components文件夹
添加icon--使用SVG Symbol
- 首先需要可以自定义webpack config
- 运行
yarn eject
- 作用时拿到webpack配置(注意运行前,需要git commit)
- 需要一个loader--使用svg-sprite-loader
- 安装
yarn add --dev svg-sprite-loader
- config
- 遇到svg格式,使用以下2个loader。webpack.config.js中:
{
test: /\.svg$/,
use: [
{loader: 'svg-sprite-loader', options: {}},
{loader: 'svgo-loader', options: {}}
]
},
- svg-sprite-loader,svgo-loader: 把引入的所有svg,合并成一个大的svg放到body里。想使用哪个svg就直接用svg,use
3. tree-shaking
import一个东西,如果没有用到一个东西,就把它从树上摇下来,从代码中删除
- 比如import这个svg x,如果不console.log(x),就会用不了
import x from 'icons/money.svg'; //svg-loader--svg-sprite-loader
import y from 'icons/tag.svg'; //svg-loader--svg-sprite-loader
console.log(x,y);
- 这是一种优化
- 使用require代替import
// import x from 'icons/money.svg'; //svg-loader--svg-sprite-loader
//import y from 'icons/tag.svg'; //svg-loader--svg-sprite-loader
require('icons/money.svg')
require('icons/tag.svg')
require('icons/chart.svg')
// console.log(x,y);
4. 取消重复 --- 封装的思想
- 取消重复,继续封装!!!
- 代码结构如下。component为共用组件。
封装1 - 把svg封装成组件<Icon>
- 直接import svg然后使用svg也行,但不灵活
1. require一个目录/文件夹(否则需要一个一个require)
//require一个目录/文件夹
let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
try {importAll(require.context('icons', true, /\.svg$/));} catch (error) {console.log(error);}
- 安装
yarn add --dev @types/webpack-env
2. icon.tsx
import React from "react";
//require一个目录/文件夹
let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
try {importAll(require.context('icons', true, /\.svg$/));} catch (error) {console.log(error);}
type Props = {
name:string
}
const Icon =(props:Props)=>{
return (
<svg fill='red' className="icon">
<use xlinkHref={'#'+props.name}></use>
</svg>
)
};
export default Icon
- 然后在需要用的地方import即可
封装2 - 导航抽离为<Nav/>
组件
import styled from "styled-components";
import {Link} from "react-router-dom";
import React from "react";
import Icon from "./Icon";
//css-in-js的方案:styled-component
const NavWrapper = styled.nav`
box-shadow:0 0 3px rgba(0,0,0,0.25);
line-height:24px;
> ul {
display:flex;
> li {
width:33.3333%;
text-align:center;
display:flex;
padding:4px 0;
flex-direction: column;
justify-content: center;
align-items: center;
.icon {
width:24px;
height:24px;
}
}
}
`
const X=()=>{
return (
<NavWrapper>
<ul>
<li>
<Icon name="tag"/>
<Link to="/tags">标签页</Link>
</li>
<li>
<Icon name="money"/>
<Link to="/money">记账</Link>
</li>
<li>
<Icon name="chart"/>
<Link to="/statistics">统计页</Link>
</li>
</ul>
</NavWrapper>
)
}
export default X;
封装3 - 布局抽离为<Layout/>
组件
import Nav from "./Nav";
import React from "react";
import styled from "styled-components";
//css-in-js的方案:styled-component
const Wrapper = styled.div`
border: 1px solid red;
height:100vh; //固定页面高度
display:flex;
flex-direction: column;
`
const Main = styled.div`
flex-grow:1;
`
const Layout=(props:any)=>{
console.log(props)
return (
<Wrapper>
<Main>
{props.children}
</Main>
<Nav></Nav>
</Wrapper>
)
}
export default Layout
5. icon点击之后可以跳转
- icon放入link里
<link>
其实是个a标签
<li>
<Link to="/tags">
<Icon name="tag"/>标签页
</Link>
</li>
- 更改css
> li {
width:33.3333%;
text-align:center;
> a{
display:flex; // 设置为flex
padding:4px 0;
flex-direction: column;
justify-content: center;
align-items: center;
.icon {
width:24px;
height:24px;
}
}
}
6. 选中icon高亮
react-router:activeclass
- 使用
<NavLink>
代替<link>
- 设置
activeClassName="selected"
, 这样标签被选中之后,就会又一个class = "selected"
<NavLink to="/tags" activeClassName="selected">
<Icon name="tag"/>
标签页
</NavLink>
&.selected{
color:red;
}
svgo-loader:让icon也跟随变色
- 设置css
&.selected{
color:red;
.icon {
fill:red;
}
}
- 使用loader:更改icon的颜色
- svg里fill属性有自带svg的颜色,现在想删除这些fill
- svgo-loader:可以删除某些svg不想要的属性
- 在webpack.config.js中
use: [
{loader: 'svg-sprite-loader', options: {}},
{loader: 'svgo-loader', options: {
plugins: [
{removeAttrs:{attrs:'fill'}}
]
}}
]