-
项目搭建
-
使用
create-react-app
命令搭建项目框架,并用yarn start
开启网页 -
使用 css reset
- 在
src/index.css
中加上@import-normalize;
默认样式
- 在
-
配置 sass
- 想让React支持sass
- 需要node-sass,它有两个缺点,下载速度慢、本地编译慢
- 于是我想改用 dart-sass 替换 node-sass
- 但是React只支持 node-sass,不支持 dart-sass
- 经过我的努力搜索和研究
- 我发现 npm 6.9 支持一个新功能,叫 package alias
yarn add node-sass@npm:dart-sass
即可偷梁换柱、瞒天过海、暗度陈仓- 最后我完成了我的目标
-
使用
styled components
-
在
App.tsx
添加如下代码并安装yarn add styled-components
import styled from 'styled-components'; const Button = styled.button` color: grey; `;
-
-
安装
react-router
yarn add react-router-dom
和yarn add --dev @types/react-router-dom
-
React Router 初体验
-
import React from "react"; import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom"; export default function App() { return ( <Router> <div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/users">Users</Link> </li> </ul> </nav> {/* A <Switch> looks through its children <Route>s and renders the first one that matches the current URL. */} <Switch> <Route path="/about"> <About /> </Route> <Route path="/users"> <Users /> </Route> <Route path="/"> <Home /> </Route> </Switch> </div> </Router> ); } function Home() { return <h2>Home</h2>; } function About() { return <h2>About</h2>; } function Users() { return <h2>Users</h2>; }
-
-
添加重定向和404界面
-
<Redirect exact from="/" to="/money/"/> <Route path="*"> <NoMatch /> </Route> function NoMatch(){ return <h2>页面不存在,你丫输错地址了吧!</h2> }
-
-
Router的两种模式
-
Hash
import { HashRouter as Router } from 'react-router-dom';
-
History
import { BrowserRouter as Router } from 'react-router-dom';
-
-
制作底部导航栏
-
新建
index.scss
用于样式的初始化-
@import-normalize; * { margin: 0;padding: 0;} * { box-sizing: border-box; } *::before { box-sizing: border-box;} *::after { box-sizing: border-box;} ul, ol {list-style: none;}
-
将
Wrapper
组件撑满整个屏幕const Wrapper = styled.div` border: 1px solid red; min-height: 100vh; //重点技巧!!!! `;
-
使用
flex
布局,尽量避免使用fixed
布局 -
让显示页面尽量高
flex-grow: 1;
-
-
-
解决跨平台字体问题
https://zenozeng.github.io/fonts.css/
-
将
Nav
组件抽离并封装成新的组件 -
使用
svg sprite loader
加载图片- 先提交完代码,然后运行
yarn eject
,此步骤不可回退,类似生孩子。 - 运行
yarn add --dev svg-sprite-loader
和yarn add --dev svgo-loader
- 通过
require('icons/tag.svg');
引入图片,而不是import,因为import会产生tree shaking
效果,必须添加console.log(...)
才能使用
- 先提交完代码,然后运行
-
将icon抽离出组件,避免重复
import React from 'react'; type Props = { name: string } const Icon = (props: Props) => { return ( <svg className="icon"> <use xlinkHref={'#' + props.name}/> </svg> ); }; export default Icon;
-
解决有许多图标而导致太多引入的问题
在Icon组件中 添加如下代码 并安装
yarn add --dev @types/webpack-env
let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext); try {importAll(require.context('icons', true, /\.svg$/));} catch (error) {console.log(error);}
-
点击导航栏高亮选项
添加
selected
样式&.selected { color: #f60; .icon { fill: #f60; } }
<NavLink to="/faq" activeClassName="selected"> FAQs </NavLink>
-
用
svgo-loader
工具批量去除svg图标的默认填充颜色{ loader: 'svgo-loader', options: { plugins: [ { name: 'removeAttrs', params: { attrs: '(fill|stroke)'} } ] } }
-
让input充满整个框,并消除选中样式
> label { display: flex; align-items: center; > span { padding-right: 16px; white-space: nowrap; } > input { display: block; width: 100%; height: 72px; background: none; border: none; } }
:focus{ outline: none; }
-
添加选中而不增加div高度
> li { width: 50%; text-align: center; padding: 16px 0; position: relative; &.selected::after { content: ''; display: block; height: 3px; background: #333; position: absolute; left: 0; bottom: 0; width: 100%; }
-
给numberpad加入清除浮动样式
.clearfix:after{ content:''; display:block; clear:both; }
-
将money组件进行模块化到money文件夹中,避免代码过多而导致阅读困难
-
将 Styled Component 改造为 Function Component
const TagsSection: React.FunctionComponent = () => {...}
-
为
标签设置点击事件
-
让
- 标签设置为单选
const onToggleTag = (tag: string) => { const index = selectedTags.indexOf(tag); if (index >= 0) { setSelectedTags(selectedTags.filter(t => t !== tag)); // 如果tag 已经选中,就复制所有没有被选中的tag,作为新的selectTag } else { setSelectedTags([tag]); // setSelectedTags([...selectedTags,tag]); } console.log(selectedTags); };
-
在备注中使用受控组件
const NoteSection: React.FunctionComponent = () => { const [note, setNote] = useState(''); console.log(note); return ( <Wrapper> <label> <span>备注</span> <input type="text" placeholder="在这里添加备注" value={note} onChange={ (e) => setNote(e.target.value)} /> </label> </Wrapper> ); };
-
在备注中使用非受控组件
const NoteSection: React.FunctionComponent = () => { const [note, setNote] = useState(''); const refInput = useRef<HTMLInputElement>(null); const onBlur = () => { if (refInput.current !== null) { console.log(refInput.current.value); setNote(refInput.current.value) } }; console.log(note); return ( <Wrapper> <label> <span>备注</span> <input type="text" placeholder="在这里添加备注" defaultValue={note} onBlur={onBlur} ref={refInput} /> </label> </Wrapper> ); };
-
关于React onChange 的触发时机
React onChange 会在你输入每一个只字的时候触发
HTML onChange 是焦点移出后再触发,早于onBlur
-
router路由的精准匹配之 exact
<Route exact path="/tags/:tag"> <Tag/> </Route>
-
牛逼的程序员不仅会写代码,还会改代码
将原来的
useState<string[]>
改为useState<id:number;name:string>
const useTags = () => {//封装一个自定义hook const [tags, setTags] = useState<string[]>(['衣', '食', '住', '行',]); return {tags, setTags}; };
const [tags, setTags] = useState<{ id: number; name: string }[]>([ {id: 1, name: '衣'}, {id: 2, name: '食'}, {id: 3, name: '住'}, {id: 4, name: '行'}, ]);
-
react router通过useParams获取参数
import {useParams} from 'react-router-dom'; type Params = { id: string } let {id} = useParams<Params>();
-
用空Icon进行占位,便于布局
<Topbar> <Icon name="left"/> <span>编辑标签</span> <Icon/> </Topbar> --------------------------------------------------------------------------- const Icon = (props: Props) => { return ( <svg className="icon"> {props.name && <use xlinkHref={'#' + props.name}/>} </svg> ); };
-
更新和删除Tag
const updateTag = (id: number, obj: { name: string }) => { setTags(tags.map(tag => tag.id === id ? {id, name: obj.name} : tag)); }; const deleteTag = (id: number) => { setTags(tags.filter(tag => tag.id !== id)); };
<li key={tag} onClick={ () => {onToggleTag(tag);} //错误写法:onClick={onToggleTag(tag)} // 箭头函数() => {onToggleTag(tag)使得函数不会立即执行 }>{tag}</li>
######
-