一.context
1.创建上下文对象
使用React.createContext创建一个上下文对象
import React from "react";
const ThemeContext = React.createContext();
export default ThemeContext;
2.类组件中使用上下文
关键属性:Provider、Consumer、contextType
- 父组件中通过Provider传递上下文数据
import React from "react";
import VoteMain from './VoteMain';
import VoteFooter from './VoteFooter';
import ThemeContext from "@/ThemeContext";
import './Vote.less';
class Vote extends React.Component {
state = {
supNum: 10,
oppNum: 5
};
change = type => {
let { supNum, oppNum } = this.state;
if (type === 'sup') {
this.setState({ supNum: supNum + 1 });
return;
}
this.setState({ oppNum: oppNum + 1 });
};
render() {
let { supNum, oppNum } = this.state;
return <ThemeContext.Provider
value={{
supNum,
oppNum,
change: this.change
}}>
<div className="vote-box">
<div className="header">
<h2 className="title">React是很棒的前端框架</h2>
<span className="num">{supNum + oppNum}</span>
</div>
<VoteMain />
<VoteFooter />
</div>
</ThemeContext.Provider>;
}
}
export default Vote;
- 子组件中通过contextType使用上下文数据
import React from "react";
import ThemeContext from "@/ThemeContext";
class VoteMain extends React.Component {
static contextType = ThemeContext;
render() {
let { supNum, oppNum } = this.context;
return <div className="main">
<p>支持人数:{supNum}人</p>
<p>反对人数:{oppNum}人</p>
</div>;
}
}
export default VoteMain;
3.子组件中通过Consumer使用上下文数据
import React from "react";
import { Button } from "antd";
import ThemeContext from "@/ThemeContext";
class VoteFooter extends React.Component {
render() {
return (
<ThemeContext.Consumer>
{(context) => {
let { change } = context;
return (
<div className="footer">
<Button type="primary" onClick={change.bind(null, "sup")}>
支持
</Button>
<Button type="primary" danger onClick={change.bind(null, "opp")}>
反对
</Button>
</div>
);
}}
</ThemeContext.Consumer>
);
}
}
export default VoteFooter;
3.函数组件中使用上下文
关键属性:Provider、Consumer、useContext
1.父组件中传递数据
import React, { useState } from "react";
import VoteMain from './VoteMain';
import VoteFooter from './VoteFooter';
import ThemeContext from "../ThemeContext";
import './Vote.less';
const Vote = function Vote() {
let [supNum, setSupNum] = useState(10),
[oppNum, setOppNum] = useState(5);
const change = type => {
if (type === 'sup') {
setSupNum(supNum + 1);
return;
}
setOppNum(oppNum + 1);
};
return <ThemeContext.Provider
value={{
supNum,
oppNum,
change
}}>
<div className="vote-box">
<div className="header">
<h2 className="title">React是很棒的前端框架</h2>
<span className="num">{supNum + oppNum}</span>
</div>
<VoteMain />
<VoteFooter />
</div>
</ThemeContext.Provider>;
};
export default Vote;
2.子组件通过useContext使用上下文数据
import React, { useContext } from "react";
import { Button } from 'antd';
import ThemeContext from "../ThemeContext";
const VoteFooter = function VoteFooter() {
let { change } = useContext(ThemeContext);
return <div className="footer">
<Button type="primary" onClick={change.bind(null, 'sup')}>支持</Button>
<Button type="primary" danger onClick={change.bind(null, 'opp')}>反对</Button>
</div>;
};
export default VoteFooter;
- 子组件通过Consumer使用上下文数据
import React, { useContext } from "react";
import { Consumer } from "../ThemeContext";
const VoteMain = function VoteMain() {
return (
<Consumer>
{(context) => {
let { supNum, oppNum } = context;
return (
<div className="main">
<p>支持人数:{supNum}人</p>
<p>反对人数:{oppNum}人</p>
</div>
);
}}
</Consumer>
);
};
export default VoteMain;
二.样式私有化
1.内联样式
通过内联样式解决样式冲突
缺点:都写在行内,不美观,冗余高,维护难
使用场景:偶尔可以对一些特定样式这样写
2.命名规范
对className有严格的命名规范!
项目中一般是以文件名 + 类名方式;
UI组件库一般采用BEM命名规范:block块-element元素-Modifier修饰符:el-button_default
3.CSSModules
以xxx.module.css格式的文件,会被默认编译成对象!react脚手架安装了一个插件帮我们做的!
Menu.module.css
.box {
background: lightpink;
}
.box .list {
font-size: 14px;
}
Menu.jsx
import React from "react";
import sty from "./Menu.module.css";
const Menu = function Menu() {
return (
<div className={sty.box}>
<ul className={sty.list}>
<li>电脑</li>
<li>家电</li>
</ul>
</div>
);
};
export default Menu;
4.react-jss
使用react-jss插件,在jsx中编写css样式
样式编写
import React from "react";
import { createUseStyles } from 'react-jss';
export const useStyles = createUseStyles({
box: {
backgroundColor: 'lightblue',
width: '300px'
},
title: {
fontSize: '20px',
color: 'red',
'&:hover': {
color: props => props.color
}
},
list: props => {
return {
'& a': {
fontSize: props.size + 'px',
color: '#000'
}
};
}
});
样式使用
import useStyles from './xxx.js'
const Nav = function Nav() {
let { box, title, list } = useStyles({
size: 14,
color: 'orange'
});
return <nav className={box}>
<h2 className={title}>购物商城</h2>
<div className={list}>
<a href="">首页</a>
<a href="">秒杀</a>
<a href="">我的</a>
</div>
</nav>;
};
export default Nav;
5.style-components
使用style-components插件,在js中编写css,vscode也有同名的代码提示插件
navStyle.js
import styled from "styled-components";
import { colorRed, colorBlue, titleSize } from './common';
/*
基于 “styled.标签名” 这种方式编写需要的样式
+ 样式要写在“ES6模板字符串”中
+ 返回并且导出的结果是一个自定义组件
如果编写样式的时候没有提示,我们可以在vscode中安装一个官方插件:vscode-styled-components
*/
export const NavBox = styled.nav`
background-color: lightblue;
width: 300px;
.title{
font-size: ${titleSize};
color: ${colorRed};
line-height: 40px;
&:hover{
color: ${colorBlue};
}
}
`;
export const NavBarBox = styled.div.attrs(props => {
return {
size: props.size || 16
}
})`
line-height: 40px;
a{
font-size: ${props => props.size}px;
color: #000;
margin-right: 10px;
&:hover{
color: ${props => props.hover};
}
}
`;
组件中使用
import React from "react";
import { NavBox, NavBarBox } from './NavStyle';
const Nav = function Nav() {
return <NavBox>
<h2 className="title">购物商城</h2>
<NavBarBox hover="#ffe58f">
<a href="/home">首页</a>
<a href="/rush">秒杀</a>
<a href="/my">我的</a>
</NavBarBox>
</NavBox>;
};
export default Nav;