欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-07-02 21:48:39
本文介绍了react 实现拖拽功能的示例代码,分享给大家,具体如下: 实现效果: 因为工作中会用到 jira 所以想实现一下相似的功能,顺便学习一下 h5 的拖拽。...

本文介绍了react 实现拖拽功能的示例代码,分享给大家,具体如下:

实现效果:

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>

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