React 实现拖拽功能的示例代码
程序员文章站
2022-07-02 21:48:39
本文介绍了react 实现拖拽功能的示例代码,分享给大家,具体如下:
实现效果:
因为工作中会用到 jira 所以想实现一下相似的功能,顺便学习一下 h5 的拖拽。...
本文介绍了react 实现拖拽功能的示例代码,分享给大家,具体如下:
实现效果:
因为工作中会用到 jira 所以想实现一下相似的功能,顺便学习一下 h5 的拖拽。不支持拖拽改变顺序,感觉有点麻烦,而且没必要。感觉相关的博文好少的,大部分都是直接上代码,没有解释。
图片默认可以拖动,其他元素的拖动效果同图片。正常的 div 是不能被拖动的,鼠标点击选择后移动没有效果,需要加 draggable="true" 使得元素可以被拖动。
拖拽相关的几个事件,有被拖动元素的事件,也有拖动进入的容器元素的事件。
被拖拽元素的事件:ondragstart,ondragend
放置元素的事件:ondragenter、ondragover、ondragleave、ondrop
顾名思义,不需要解释。
需要注意是 ondragover 的默认事件 reset the current drag operation to "none". 所以想让一个元素可放置,需要重写 ondragover
element.ondragover = event => { event.preventdefault(); // ... }
当一个元素是可放置的,拖拽经过时鼠标会变成加号(cursor: copy;)
有一个对象 datatransfer 可以用来存储拖拽数据。
dragele.ondragstart = e => e.datatransfer.setdata('item', e.target.id);
拖拽开始时触发,把被拖拽元素的 id 存入 e.datatransfer
然后在 ondrop 的时候 可以获取到这个值 (ondragenter、ondragover、ondragleave 获取不到...)
putele.ondrop = function(e) { let id = e.datatransfer.getdata('item'); // ... }
简单的应用:
<!doctype html> <html lang="zh"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>document</title> <style> .wrapper {display: flex;border: 1px solid orangered;padding: 10px;} .col {border: 1px solid #808080;height: 500px;width: 200px;margin: 0 10px;padding: 10px;} .item {border: 1px solid #808080;margin: 5px 0;} </style> </head> <body> <div class="wrapper"> <div class="col1 col"> <div class="item" id="item1" draggable="true">item1</div> <div class="item" id="item2" draggable="true">item2</div> <div class="item" id="item3" draggable="true">item3</div> </div> <div class="col2 col"></div> <div class="col3 col"></div> <div class="col4 col"></div> </div> <script> let cols = document.getelementsbyclassname('col'); for (let col of cols) { col.ondragenter = e => { console.log('放置元素 ondragenter', '<' + e.datatransfer.getdata('item') + '>'); } col.ondragover = e => { e.preventdefault(); console.log('放置元素 ondragover', '<' + e.datatransfer.getdata('item') + '>'); } col.ondragleave = e => { console.log('放置元素 ondragleave', '<' + e.datatransfer.getdata('item') + '>'); } col.ondrop = function(e) { console.log('放置元素 ondrop', '<' + e.datatransfer.getdata('item') + '>'); this.append(document.getelementbyid(e.datatransfer.getdata('item'))); } } let items = document.getelementsbyclassname('item'); for (let item of items) { item.ondragstart = e => { console.log('拖拽元素 ondragstart'); e.datatransfer.setdata('item', e.target.id); } item.ondragend = e => { console.log('拖拽元素 ondragend'); } } </script> </body> </html>
文章开头部分的 react 写的 demo
<!doctype html> <html> <head> <meta charset="utf-8"> <title></title> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> <style> .item { border: 1px solid #1da921; width: 180px; border-radius: 5px; box-shadow: 0 0 5px 0 #b3b3b3; margin: 5px auto; background: #fff; } .item.active { border-style: dashed; } .item-header { font-size: 12px; color: #9e9e9e; padding: 3px 5px; } .item-main { padding: 5px; font-size: 14px; color: #424242; height: 36px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } .item-header-point { background: #ccc; float: right; padding: 0 4px; min-width: 10px; text-align: center; color: #fff; border-radius: 50%; } .col { border: 1px solid #d2d2d2; flex-grow: 1; width: 180px; height: 100%; margin: 0 2px; background: #eee; flex-grow: 1; display: flex; flex-direction: column; } .col-header { height: 40px; line-height: 40px; background: #1da921; color: #fff; text-align: center; } .col-main { overflow: auto; flex-grow: 1; } .col-main.active { background: #00ad23; opacity: 0.1; } .task-wrapper { display: flex; height: 400px; width: 700px; } </style> </head> <body> <div id="app"></div> <script type="text/babel"> const status_todo = 'status_todo'; const status_doing = 'status_doing'; const status_done = 'status_done'; const status_code = { status_todo: '待处理', status_doing: '进行中', status_done: '已完成' } let tasks = [{ id: 0, status: status_todo, title: '每周七天阅读五次,每次阅读完要做100字的读书笔记', username: '小夏', point: 10 }, { id: 1, status: status_todo, title: '每周七天健身4次,每次健身时间需要大于20分钟', username: '橘子????', point: 5 }, { id: 2, status: status_todo, title: '单词*100', username: '┑( ̄д  ̄)┍', point: 2 }, { id: 3, status: status_todo, title: '单词*150', username: '┑( ̄д  ̄)┍', point: 2 }, { id: 4, status: status_todo, title: '单词*200', username: '┑( ̄д  ̄)┍', point: 2 }, { id: 5, status: status_todo, title: '单词*250', username: '┑( ̄д  ̄)┍', point: 2 }] class taskitem extends react.component { handledragstart = (e) => { this.props.ondragstart(this.props.id); } render() { let { id, title, point, username, active, ondragend } = this.props; return ( <div ondragstart={this.handledragstart} ondragend={ondragend} id={`item-${id}`} classname={'item' + (active ? ' active' : '')} draggable="true" > <header classname="item-header"> <span classname="item-header-username">{username}</span> <span classname="item-header-point">{point}</span> </header> <main classname="item-main">{title}</main> </div> ); } } class taskcol extends react.component { state = { in: false } handledragenter = (e) => { e.preventdefault(); if (this.props.candragin) { this.setstate({ in: true }) } } handledragleave = (e) => { e.preventdefault(); if (this.props.candragin) { this.setstate({ in: false }) } } handledrop = (e) => { e.preventdefault(); this.props.dragto(this.props.status); this.setstate({ in: false }) } render() { let { status, children } = this.props; return ( <div id={`col-${status}`} classname={'col'} ondragenter={this.handledragenter} ondragleave={this.handledragleave} ondragover={this.handledragenter} ondrop={this.handledrop} draggable="true" > <header classname="col-header"> {status_code[status]} </header> <main classname={'col-main' + (this.state.in ? ' active' : '')}> {children} </main> </div> ); } } class app extends react.component { state = { tasks: tasks, activeid: null } /** * 传入被拖拽任务项的 id */ ondragstart = (id) => { this.setstate({ activeid: id }) } dragto = (status) => { let { tasks, activeid} = this.state; let task = tasks[activeid]; if (task.status !== status) { task.status = status; this.setstate({ tasks: tasks }) } this.cancelselect(); } cancelselect = () => { this.setstate({ activeid: null }) } render() { let { tasks, activeid } = this.state; let { ondragstart, ondragend, cancelselect } = this; return ( <div classname="task-wrapper"> { object.keys(status_code).map(status => <taskcol status={status} key={status} dragto={this.dragto} candragin={activeid != null && tasks[activeid].status !== status}> { tasks.filter(t => t.status === status).map(t => <taskitem key={t.id} active={t.id === activeid} id={t.id} title={t.title} point={t.point} username={t.username} ondragstart={ondragstart} ondragend={cancelselect} />) } </taskcol> ) } </div> ) } } reactdom.render( <app />, document.getelementbyid('app') ); </script> </body> </html>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。