React:记账本01--基础配置和布局

327 阅读5分钟

准备工作

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.目录解构说明

2IhQm9.md.png

tsx和ts的区别

  1. .js和.jsx
  • .js正常的js
  • .jsx支持标签的js
  1. .ts和.tsx
  • .ts正常ts
  • .tsx支持标签的ts

对比vue和react的目录

  1. react更简洁
  • create-react-app生成的几乎只有一个src和一个public
  1. 内置功能更少
  • 没有自带router
  • 没有自带redux
  • 没有自带scss

5. StrictMode

StrictMode检查有没有用错的地方,纠正代码标签使用是否正确。

 <React.StrictMode>
    <App />
  </React.StrictMode>,

6. css相关配置

css normalize

  1. 在index.css添加
@import-normalize; /* bring in normalize.css styles */
  1. 作用:保证页面在不同浏览器上默认样式相近
  2. IED不认识这个语法会报错,忽略即可。
  3. 个人认为这个东西没什么用,默认样式会被覆盖。
  4. 文档介绍
  5. css normalise和cssrest区别

scss

  1. 文档介绍
  2. 使用dart-sass代替node-sass
  • node-scss: 下载失败:
  • 1.可能下载不成功
    1. 本地编译比减慢
  1. react dart-scss会报错,使用
yarn add --dev node-sass@npm:dart-sass@1.25.0

表示在本地安装node-sass,但实际上用dart-sass

  1. 然后将所有.css改为.scss
  2. 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
  1. 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引用更方便

  1. vue里面,使用@表示src/目录
  2. react不同
  • 不需要@
  • 可以使用@import 'xxx/yyy'来引入src/xxx/yyy.scss
  • 配置文档
  1. JS也不需要@
  • 在tsconfig.json添加一行
"baseUrl":"src"
  1. 为了配置方便,创建helper.scss
  • 里面防止变量,函数等共用的东西
  • 比如
$red:#f00
  • index.scss里引用helper
@import 'helper'

7. css-in-js的方案:styled-component

css就在js里面,github

  1. 安装
yarn add styled-components
yarn add --dev @types/styled-components

  1. 不是重新写样式,而是让标签自带样式
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;

  1. 就是把css翻译为style标签

8. 配置总结

  1. 使用ts开发react
  • 配置tsconfig.json后,可以使用import 'xxx' 以引用src/xxx
  1. css方面
  • 使用dart-sass编译scss至css
  • 直接import 'xxx' 引入src/xxx
  • 变量和函数放入src/helper.scss
  • 使用styled-components这种css-in-js的方案写css

开始制作

1. 制作底部导航

  1. 安装react-router
yarn add react-router-dom
yarn add --dev @types/react-router-dom

  1. 默认进入哪个页面
   <Redirect exact from='/' to='/money'></Redirect>
  • 如果不小心输入错误地址
   <Route path="*">
              <NoMatch />
   </Route>
            
    function NoMatch(){
  return (
      <div>
        页面不存在
      </div>
  )
}        
  1. 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>
  1. router 有2种模式
  • history模式
  • 切换hash
import { HashRouter as Router} from "react-router-dom";

2. 导航栏的定位

  1. fixed定位会有bug,能用就不用,手机上会有问题
  2. 用flex,弹性布局
  3. 夸平台中文字体css解决方案
  1. 封装:Nav单独放入components文件夹

添加icon--使用SVG Symbol

  1. 首先需要可以自定义webpack config
  • 运行
yarn eject
  • 作用时拿到webpack配置(注意运行前,需要git commit)
  1. 需要一个loader--使用svg-sprite-loader
  • 安装
yarn add --dev svg-sprite-loader
  1. 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为共用组件。 2TRW0s.png

封装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点击之后可以跳转

  1. icon放入link里
  • <link>其实是个a标签
<li>
    <Link to="/tags">
        <Icon name="tag"/>标签页
    </Link>
</li>
  1. 更改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

  1. 使用<NavLink>代替<link>
  2. 设置activeClassName="selected", 这样标签被选中之后,就会又一个class = "selected"
<NavLink  to="/tags" activeClassName="selected">
    <Icon name="tag"/>
    标签页
</NavLink>
  &.selected{
        color:red;
    }

svgo-loader:让icon也跟随变色

  1. 设置css
&.selected{
    color:red;
    .icon {
       fill:red;
    }
}
  1. 使用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'}}
            ]
          }}
]