样式模块化
有时候我们会遇到这样的问题,有两个css对一个class声明了样式,这样的话后引入的css会覆盖前面的css样式,导致样式冲突,那么我们怎么解决这种问题呢,我们可以使用样式的模块化,我们起名一个index.module.css和一个content.module.css
- 我们在代码中这样使用
import React from "react";
import index from "./css/index.module.css";
import content from "./css/content.module.css";class Hello extends React.Component {render() {console.log("i am render")return (<ul><h1 className={index.title}>i am index.css</h1><h1 className={content.title}>i am content.css</h1></ul>)}
}
//导出组件
export default Hello;
Webstorm中的快捷键
- rcc+tab键:用ES6模块系统创建一个React组件类
import React, {Component} from 'react';class Hello extends Component {render() {return (<div></div>);}
}export default Hello;
- rccp+tab键:创建一个带有PropTypes和ES6模块系统的React组件类
import React, {Component} from 'react';
import PropTypes from 'prop-types';class Hello extends Component {render() {return (<div></div>);}
}Hello.propTypes = {};export default Hello;
- rcfc+tab键:创建一个带有PropTypes和所有生命周期方法以及ES6模块系统的React组件类
- rcjc+tab键:用ES6模块系统创建一个React组件类(无导出)
- rdp+tab键:快速生成defaultProps
- rpc+tab键:用PropTypes和ES6 moudle系统创建一个React纯组件类
- rrc+tab键:创建一个连接到redux的React组件类
- rrdc+tab键:创建一个通过dispatch连接到redux的React组件类
- rsc+tab键:创建没有PropTypes和ES6模块系统的无状态React组件
- rscp+tab键:创建有PropTypes和ES6模块系统的无状态React组件
- rsf+tab键:以命名函数的形式创建无状态的React组件,不使用PropTypes
- rsfp+tab键:使用PropTypes将无状态的React组件作为命名函数创建
- rsi+tab键:创建无状态的React组件,不使用PropTypes和ES6模块系统,但使用隐式返回和道具
- rwwd+tab键:在没有导入的情况下,在ES6模块系统中创建一个有构造函数、空状态、proptypes和导出的React组件类。(主要用于React时,proptype由webpack提供插件提供)
组件化编码
我们通过前面应该也能认识到,我们写react,包括npm运行react,其实都是从index.js入口文件开始,那么index.js的格式至关重要
//引入核心库
import React from 'react';
//引入dom库
import ReactDOM from 'react-dom';
//引入组件
import Hello from './components/Hello';
ReactDOM.render(<Hello />,document.getElementById('root'))
拆分组件的原则
-
单一职责原则:每个组件只负责一项功能,这样可以使组件的代码更加简洁易读,并且方便维护和重用。
-
可复用性:每个组件都应该尽量独立,以便在其他地方重复使用。
-
组件之间的耦合度:组件之间应该尽量避免耦合,这样可以使得组件的代码更加灵活,便于维护和修改。
-
让组件尽可能小:尽可能使组件的代码行数少,这样可以使代码更易读,并且方便维护。
-
可读性:组件的代码应该有良好的结构,并且有适当的注释,便于阅读和理解。
案列 TodoList
页面渲染
我先把一个没有任何功能的页面渲染出来,给一些初始数据
- 我们在入口文件中,分别声明 引入的核心文件,dom库,和组件
//引入核心库
import React from 'react';
//引入dom库
import ReactDOM from 'react-dom';
//引入组件
import App from "./App";
ReactDOM.render(<App />,document.getElementById('root'))
- 在App组件初始化一些数据并返回页面结构,并将初始化数据通过props传给list
import React, {Component} from 'react';
import "./App.css"
import Header from "./components/Header/Header"
import Footer from "./components/Footer/Footer"
import List from "./components/List/List"
class App extends Component {//初始状态state={todos:[{id:1,text:"吃饭",done:false},{id:2,text:"睡觉",done:false},{id:3,text:"打豆豆",done:false},{id:4,text:"看动画",done:false}]}render() {return (<div className="todo-container"><div className="todo-wrap">{/*引入header组件*/}<Header />{/*引入list组件*/}<List data={this.state.todos} />{/*引入Footer组件*/}<Footer /></div></div>);}
}export default App;
- List.jsx
import React, {Component} from 'react';
import Item from "../Item/Item";
import "./List.css"
class List extends Component {//限制属性类型render() {const todos = this.props.data;return (<ul className="todo-main">{todos.map((todo, index) => {// 将todo对象作为props传给Item组件 ...默认和对象同名return <Item key={todo.id} {...todo}></Item>;})}</ul>);}
}export default List;
- Item.jsx
import React, {Component} from 'react';
import "./Item.css"class Item extends Component {render() {const {id,text,done}=this.propsreturn (<li style={{backgroundColor: 'white'}}><label ><input type="checkbox"/><span>{text}</span></label><button className="btn btn-danger" style={{display:'none'}}>删除</button></li>);}
}
export default Item;
- Header.jsx
import React, {Component} from 'react';class Header extends Component {render() {return (<div className="todo-header"><input type="text" placeholder="请输入你的任务名称,按回车键确认"/></div>);}
}
export default Header;
- Footer.jsx
import React, {Component} from 'react';class Footer extends Component {render() {return (<div className="todo-footer"><label><input type="checkbox"/><span><span>已经完成2/全部5</span></span></label><button className="btn btn-danger">清除已完成任务</button></div>);}
}export default Footer;
- 最终样式如下
功能实现
鼠标悬浮
- 首先我们来实现第一个功能,从简单功能入手,鼠标悬浮,列表背景色变色,并展示删除按钮,触发事件是
onMouseEnter
,鼠标离开恢复原状,触发事件是onMouseLeave
,展示是否完成的状态,我们开始编写
class Item extends Component {//定义状态state={mouse:false}//接收参数handleMouse=(flag)=>{return ()=>{this.setState({mouse:flag})}}render() {const {id,text,done}=this.propsconst flag=this.state.mousereturn ( //传入参数<li style={{backgroundColor: flag?'#ddd':'white'}} onMouseEnter={this.handleMouse(true)}onMouseLeave={this.handleMouse(false)}><label ><input type="checkbox" checked={done}/><span>{text}</span></label><button className="btn btn-danger" style={{display:flag?'block':'none'}}>删除</button></li>);}
}
勾选和删除
- 实现勾选和删除功能,当点击选中按钮的时候,触发的操作是
onChange
,删除按钮的触发事件是onClick
,我们来实现一下,因为我们操作的数据来源于App.jsx的state,为了方便操作数据,我们将方法写在App.jsx里面,然后通过props传递给组件
updateTodo=(id,done)=>{const todos=this.state.todos//遍历找到对应的todo,创建一个新的数组对象const newTodos=todos.map((todo)=>{if (todo.id===id){//改变状态return {...todo,done:done}}else{return todo}})this.setState({todos:newTodos})}deleteTodo=(id)=>{const todos=this.state.todosconst newTodos=todos.filter((todo)=>{return todo.id !==id})this.setState({todos:newTodos})}
- Item.jsx
handelChange=(id)=>{return (e)=>{//根据id和checked状态更新数据this.props.updateTodo(id,e.target.checked)}}del=(id)=>{return ()=>{this.props.deleteTodo(id)}}render() {const {id,text,done}=this.propsconst flag=this.state.mousereturn ( //传入参数<li style={{backgroundColor: flag?'#ddd':'white'}} onMouseEnter={this.handelMouse(true)}onMouseLeave={this.handelMouse(false)}><label ><input type="checkbox" checked={done} onChange={this.handelChange(id)}/><span>{text}</span></label><button className="btn btn-danger" onClick={this.del(id)} style={{display:flag?'block':'none'}}>删除</button></li>);}
添加
- 接下来我们再实现一个添加todo的功能,触发事件就是Onkeyup
App.js
addTodo=(todo)=>{const todos=this.state.todosconst newTodos=[...todos,todo]console.log(newTodos);this.setState({todos:newTodos})}
header.jsx
addTodo = (e) => {// console.log(e);const {keyCode, target} = eif (keyCode === 13) {const todo = {id: nanoid(),text: target.value,done: false}// console.log(todo);this.props.addTodo(todo);target.value = '';}}
全选和一键清除
- app.js
checkAll=(bool)=>{//全选或者取消全选const todos=this.state.todosconst newTodos=todos.map((todo)=>{return {...todo,done:bool}})this.setState({todos:newTodos})}delAll=()=>{const todos=this.state.todosconst newTodos=todos.filter((todo)=>{return !todo.done})this.setState({todos:newTodos})}
- footer.jsx
class Footer extends Component {state = {checked: false};//如果是状态false 点击后全选中checkAll = () => {const checked=this.state.checked;this.props.checkAll(!checked);this.setState({checked: !this.state.checked});};delAll = () => {this.props.delAll();};render() {const {todos} = this.props;const total=todos.lengthconst doneCount=todos.reduce((prev,cur)=>{return prev+(cur.done?1:0);},0)return (<div className="todo-footer"><label><input onChange={this.checkAll} checked={this.state.checked} type="checkbox"/><span><span>已经完成{doneCount}/全部{total}</span></span></label><button className="btn btn-danger" onClick={this.delAll}>清除已完成任务</button></div>);}
}
react的事件监听大全
react所有事件监听