当前位置: 移动技术网 > IT编程>开发语言>JavaScript > React 实现拖拽功能的示例代码

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

2019年06月01日  | 移动技术网IT编程  | 我要评论

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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网