react+react-beautiful-dnd實(shí)現(xiàn)代辦事項(xiàng)思路詳解
react+react-beautiful-dnd應(yīng)用
效果預(yù)覽
實(shí)現(xiàn)思路
index.js入口文件配置
import React from 'react' import ReactDOM from 'react-dom' import App from './App' import 'bulma-start/css/main.css' // 引入bulma樣式 ReactDOM.render( <App/>, document.getElementById('root') )
app.jsx主頁(yè)面配置
Provider格式
return( <Provider value={{ '要在tree傳遞的名字':this.'具體屬性或方法' }}> 自己的代碼 </Provider> )
import React,{ Component} from "react"; import TodoHeader from './components/TodoHeader.jsx' import TodoInput from "./components/TodoInput"; import TodoList from "./components/TodoList"; import TodoFoot from "./components/TodoFoot"; import {Provider} from "./untils/with-context" // 引入TodoContext組件 export default class App extends Component{ state ={ todos:Array(6).fill(null).map((_,index)=>({ id:index++, title:'待辦事項(xiàng)'+index++, completed: Math.random()>0.5, })) } // 拖拽后的更新state處理函數(shù) drag(newTodos){ this.setState({ todos:[...newTodos], }) } // 添加事件處理函數(shù) addTodoItem=title=>{ this.setState({ todos:[ ...this.state.todos, { /* id:this.state.todos[this.state.todos.length-1]+1, * 更新setState是異步的,這里是拿不到最新的state */ id:Math.random(), title, completed:false, } ] }) } // 刪除事件處理函數(shù) delTodo=id=>{ this.setState({ todos:this.state.todos.filter(todo=>todo.id !==id) }) } // 更改事件狀態(tài)處理函數(shù) changComple=id=>{ this.setState({ todos:this.state.todos.map(todo=>{ if(todo.id === id){ todo.completed=!todo.completed } return todo }) }) } // 根據(jù)總選框狀態(tài)設(shè)置每個(gè)單選框狀態(tài) allCheckbox=(status)=>{ this.setState({ todos:this.state.todos.map(todo=>{ todo.completed=status return todo }) }) } // 刪除已完成事件 delCompelted=()=>{ this.setState({ todos:this.state.todos.filter(todo=>!todo.completed) }) } render() { return( <Provider value={{ todos:this.state.todos, changComple:this.changComple, delTodo:this.delTodo, allCheckbox:this.allCheckbox, delCompelted:this.delCompelted, }}> <article className="panel is-success"> <TodoHeader/> <TodoInput add={this.addTodoItem}/> <TodoList todos={this.state.todos} drag={this.drag.bind(this)}/> <TodoFoot/> </article> </Provider> ) } }
untils/with-context.js封裝工具todoContext
import {createContext} from "react"; // 創(chuàng)建creatContext對(duì)象 const TodoContext = createContext() // 結(jié)構(gòu)要用到的React組件 const { Provider, // 生產(chǎn)組件 Consumer, // 消費(fèi)組件 } = TodoContext export { Provider, Consumer, TodoContext, }
components/TodoHeader.jsx頁(yè)面頭部
import React, { Component } from 'react' export default class TodoHeader extends Component { render() { return ( <p className="panel-heading"> 待辦事項(xiàng)列表 </p> ) } }
components/TodoInput.jsx該文件主要負(fù)責(zé)添加事件
import React, {Component, createRef} from "react"; export default class TodoInput extends Component{ state={ inputValue:'輸入代辦事件', // 定義input輸入框內(nèi)容 } inputRef=createRef() // 定義ref綁定DOM元素,作用是為下面自動(dòng)獲取焦點(diǎn)做準(zhǔn)備 // 輸入框中輸入的內(nèi)容設(shè)置給state作用1:輸入框內(nèi)容改變2:后面提交添加事件拿到input內(nèi)容 handleChang=Event=>{ this.setState({ inputValue:Event.target.value }) } // 添加代辦事件 handleDown=Event=>{ // 驗(yàn)證下是否為空 if(this.state.inputValue==='' || this.state.inputValue===null) return if(Event.keyCode ===13){ this.add() } } // 添加處理函數(shù) add=()=>{ // add方法通過(guò)props從App傳入 this.props.add(this.state.inputValue) this.state.inputValue='' // ref綁定后通過(guò)inputRef.current拿到DOM元素 this.inputRef.current.focus() } render() { return( <div className="panel-block"> <p className="control has-icons-left"> <input className="input is-success" type="text" placeholder="輸入代辦事項(xiàng)" value={this.state.inputValue} onChange={this.handleChang} onKeyDown={this.handleDown.bind(this)} //該變this指向 ref={this.inputRef} /> </p> </div> ) } }
介紹下react-beautiful-dnd處理函數(shù)
官方解析圖
格式DragDropContext最外面盒子Droppable第二層盒子
<DragDropContext onDragEnd={this.onDragEnd}> <Droppable droppableId='columns'> {provided=>( <* ref={provided.innerRef} {...provided.droppableProps} // 官方固定格式 > 自己的代碼 <*/> {provided.placeholder} )} </Droppable> </DragDropContext>
格式Draggable最里面盒子
<Draggable draggableId={String(id)} index={this.props.index}> {provided=>( <* {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} > 自己的代碼 <*/> {provided.placeholder} )} </Draggable>
一但移動(dòng)(從第5個(gè)事件移動(dòng)到第4個(gè)事件)onDragEnd回調(diào)函數(shù)打印結(jié)果console.log(result)
{draggableId: '5', type: 'DEFAULT', source: {…}, reason: 'DROP', mode: 'FLUID', …} combine: null destination: {droppableId: 'columns', index: 4} // 移動(dòng)到第4個(gè)事件 draggableId: "5" mode: "FLUID" reason: "DROP" source: {index: 5, droppableId: 'columns'} // 移動(dòng)的第5個(gè)事件 type: "DEFAULT" [[Prototype]]: Object
components/TodoList.jsx
import React,{Component} from "react"; import TodoItem from "./TodoItem"; import PropTypes from 'prop-types' import {DragDropContext} from 'react-beautiful-dnd' import {Droppable} from 'react-beautiful-dnd' export default class TodoList extends Component{ // 類(lèi)型檢查 static propTypes={ todos:PropTypes.array.isRequired, } // 默認(rèn)值 static defaultProps = { todos: [], } // 根據(jù)choice數(shù)值決定渲染事項(xiàng) state={ choice:1 } // react-beautiful-dnd核心處理函數(shù),負(fù)責(zé)交換后的處理(可以自定義) onDragEnd=result=>{ console.log(result) const {destination,source,draggableId}=result if(!destination){ // 移動(dòng)到了視圖之外 return } if( // 移動(dòng)到原來(lái)位置,也就是位置不變 destination.droppableId===source.droppableId && destination.index===source.index ){ return;} const newTaskIds=Array.from(this.props.todos) // 轉(zhuǎn)化為真正的數(shù)組 newTaskIds.splice(source.index,1) // 刪除移動(dòng)的數(shù)組 newTaskIds.splice(destination.index,0,this.props.todos[source.index]) // 在移動(dòng)到的位置初放置被刪除的數(shù)組 // 調(diào)用App文件中的drag執(zhí)行交換后的更改 this.props.drag(newTaskIds) } // 點(diǎn)擊時(shí)渲染不同DOM choice=(num)=>{ this.setState({ choice:num }) } render() { let uls=null if(this.state.choice===1){ uls=(<DragDropContext onDragEnd={this.onDragEnd}> <Droppable droppableId='columns'> {provided=>( <ul ref={provided.innerRef} {...provided.droppableProps} > {this.props.todos.length>0 ? this.props.todos.map((todo,index)=>{ return ( <TodoItem key={todo.id} todo={todo} index={index}/> ) }) :<div>添加代辦事項(xiàng)</div> } {provided.placeholder} </ul> )} </Droppable> </DragDropContext>) }else if(this.state.choice===2){ // 過(guò)濾下事件 let newtodos=this.props.todos.filter(todo=> todo.completed) uls=(<DragDropContext onDragEnd={this.onDragEnd}> <Droppable droppableId='columns'> {provided=>( <ul ref={provided.innerRef} {...provided.droppableProps} > {newtodos.length>0 ? newtodos.map((todo,index)=>{ return ( <TodoItem key={todo.id} todo={todo} index={index}/> ) }) :<div>暫無(wú)已完成事件</div> } {provided.placeholder} </ul> )} </Droppable> </DragDropContext>) }else if(this.state.choice===3){ // 過(guò)濾下事件 let newtodos=this.props.todos.filter(todo=> !todo.completed) uls=(<DragDropContext onDragEnd={this.onDragEnd}> <Droppable droppableId='columns'> {provided=>( <ul ref={provided.innerRef} {...provided.droppableProps} > {newtodos.length>0 ? newtodos.map((todo,index)=>{ return ( <TodoItem key={todo.id} todo={todo} index={index}/> ) }) :<div>暫無(wú)未完成事件</div> } {provided.placeholder} </ul> )} </Droppable> </DragDropContext>) } return( <> <p className="panel-tabs"> <a className="is-active" onClick={()=>this.choice(1)}>所有</a> <a onClick={()=>this.choice(2)}>已完成</a> <a onClick={()=>this.choice(3)}>未完成</a> </p> {uls} </> ) } }
components/TodoFoot.jsx Consumer格式
return( <Consumer> {value=>{ const {結(jié)構(gòu)要用的屬性或方法的名字} = value return( 自己的代碼,value中含有Provider中傳入的所有值 ) }} </Consumer> )
import React,{Component} from "react"; import {Consumer} from '../untils/with-context' export default class TodoFoot extends Component{ render() { return( <Consumer> { value => { const {allCheckbox,todos,delCompelted} = value const completedNum =todos.filter(todo=>todo.completed).length const AllChecked =todos.length?todos.every(todo=>todo.completed):false return( <div> <label className="panel-block"> <input type="checkbox" checked={AllChecked} onChange={(event)=>allCheckbox(event.target.checked)}/>全選 <span>已完成{completedNum}</span> <span>一共{todos.length}</span> </label> <div className="panel-block"> <button className="button is-success is-outlined is-fullwidth" onClick={delCompelted}> 刪除已完成 </button> </div> </div> ) } } </Consumer> ) } }
package.json中的三方包資源
{ "name": "react-demo", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "bulma-start": "^0.0.5", "react": "^17.0.2", "react-beautiful-dnd": "^13.1.0", "react-dom": "^17.0.2", "react-native": "^0.68.2", "react-scripts": "4.0.3", "redux-persist": "^6.0.0", "store": "^2.0.12", "web-vitals": "^1.0.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }
到此這篇關(guān)于react+react-beautiful-dnd實(shí)例代辦事項(xiàng)的文章就介紹到這了,更多相關(guān)react代辦事項(xiàng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react路由守衛(wèi)的實(shí)現(xiàn)(路由攔截)
react不同于vue,通過(guò)在路由里設(shè)置meta元字符實(shí)現(xiàn)路由攔截。本文就詳細(xì)的介紹一下,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08React18系列commit從0實(shí)現(xiàn)源碼解析
這篇文章主要為大家介紹了React18系列commit從0實(shí)現(xiàn)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01簡(jiǎn)談創(chuàng)建React Component的幾種方式
這篇文章主要介紹了創(chuàng)建React Component的幾種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下2019-06-06解決React報(bào)錯(cuò)Parameter 'props' implicitly&nb
這篇文章主要為大家介紹了React報(bào)錯(cuò)Parameter 'props' implicitly has an 'any' type的解決處理方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12詳解React-Router中Url參數(shù)改變頁(yè)面不刷新的解決辦法
這篇文章主要介紹了詳解React-Router中Url參數(shù)改變頁(yè)面不刷新的解決辦法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05React hook 'useState' is calle
這篇文章主要為大家介紹了React hook 'useState' is called conditionally報(bào)錯(cuò)解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12react.js 父子組件數(shù)據(jù)綁定實(shí)時(shí)通訊的示例代碼
本篇文章主要介紹了react.js 父子組件數(shù)據(jù)綁定實(shí)時(shí)通訊的示例代碼,2017-09-09