樣式模塊化
有時候我們會遇到這樣的問題,有兩個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所有事件監聽