首页 > 编程 > JavaScript > 正文

React 实现拖拽功能的示例代码

2019-11-19 12:19:15
字体:
来源:转载
供稿:网友

本文介绍了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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表