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


Posted in Javascript onJanuary 06, 2019

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

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

Javascript 相关文章推荐
简洁Ajax函数处理(示例代码)
Nov 15 Javascript
js实现带圆角的两级导航菜单效果代码
Aug 24 Javascript
JavaScript必知必会(十) call apply bind的用法说明
Jun 08 Javascript
1秒50万字!js实现关键词匹配
Aug 01 Javascript
JavaScript数组操作函数汇总
Aug 05 Javascript
javascript 动态生成css代码的两种方法
Mar 17 Javascript
javascript 开发之百度地图使用到的js函数整理
May 19 Javascript
使用jQuery实现动态添加小广告
Jul 11 jQuery
JQuery判断radio单选框是否选中并获取值的方法
Jan 17 jQuery
微信小程序实现判断是分享到群还是个人功能示例
May 03 Javascript
JAVA面试题 static关键字详解
Jul 16 Javascript
Vue中遍历数组的新方法实例详解
Jul 21 Javascript
Next.js实现react服务器端渲染的方法示例
Jan 06 #Javascript
vue.js引入外部CSS样式和外部JS文件的方法
Jan 06 #Javascript
Bootstrap4 gulp 配置详解
Jan 06 #Javascript
jQuery实现获取当前鼠标位置并输出功能示例
Jan 05 #jQuery
node.js连接mysql与基本用法示例
Jan 05 #Javascript
Node.js Buffer模块功能及常用方法实例分析
Jan 05 #Javascript
Node.js net模块功能及事件监听用法分析
Jan 05 #Javascript
You might like
PHP验证码类代码( 最新修改,完全定制化! )
2010/12/02 PHP
PHP获取短链接跳转后的真实地址和响应头信息的方法
2014/07/25 PHP
ThinkPHP模板Volist标签嵌套循环输出多维数组的方法
2016/03/23 PHP
PHP操作Redis数据库常用方法示例
2018/08/25 PHP
jquery实现在页面加载的时自动为日期插件添加当前日期
2014/08/20 Javascript
JavaScript数组迭代器实例分析
2015/06/09 Javascript
利用BootStrap弹出二级对话框的简单实现方法
2016/09/21 Javascript
BootStrap中jQuery插件Carousel实现轮播广告效果
2017/03/27 jQuery
Vue 仿QQ左滑删除组件功能
2018/03/12 Javascript
详解vue更改头像功能实现
2019/04/28 Javascript
在Vue中创建可重用的 Transition的方法
2020/06/02 Javascript
举例讲解Python程序与系统shell交互的方式
2015/04/09 Python
一些常用的Python爬虫技巧汇总
2016/09/28 Python
SQLite3中文编码 Python的实现
2017/01/11 Python
为什么入门大数据选择Python而不是Java?
2018/03/07 Python
python中的不可变数据类型与可变数据类型详解
2018/09/16 Python
PyQt5 实现给窗口设置背景图片的方法
2019/06/13 Python
python实现抠图给证件照换背景源码
2019/08/20 Python
基于Python实现剪切板实时监控方法解析
2019/09/11 Python
pytorch 模拟关系拟合——回归实例
2020/01/14 Python
Windows下pycharm安装第三方库失败(通用解决方案)
2020/09/17 Python
美国设计师精美珠宝购物网:Netaya
2016/08/28 全球购物
Hotter Shoes英国官网:英伦风格,舒适的鞋子
2017/12/28 全球购物
英国灯具和灯泡网上商店:Lights.co.uk
2018/02/02 全球购物
Solid & Striped官网:美国泳装品牌
2019/06/19 全球购物
西班牙最好的在线购买葡萄酒的商店:Vinoseleccion
2019/10/30 全球购物
简历自我评价模版
2014/01/31 职场文书
淘宝客服专员岗位职责
2014/04/11 职场文书
《春到梅花山》教学反思
2014/04/16 职场文书
化工工艺设计求职信
2014/06/25 职场文书
2014党委书记四风对照检查材料思想汇报
2014/09/21 职场文书
自荐信格式范文
2015/03/04 职场文书
投诉信范文
2015/07/02 职场文书
2015年计算机教师工作总结
2015/07/22 职场文书
2015年教学副校长工作总结
2015/07/22 职场文书
Spring整合Mybatis的全过程
2021/06/28 Java/Android