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 相关文章推荐
google 搜索框添加关键字实现代码
Apr 24 Javascript
使用jQuery避免鼠标双击的解决方案
Aug 21 Javascript
from 表单提交返回值用post或者是get方法实现
Aug 21 Javascript
JS+CSS设置img在DIV中只显示Img垂直居中的部分
Oct 24 Javascript
js使用Array.prototype.sort()对数组对象排序的方法
Jan 28 Javascript
JS判断日期格式是否合法的简单实例
Jul 11 Javascript
AngularJS删除路由中的#符号的方法
Sep 20 Javascript
微信小程序 倒计时组件实现代码
Oct 24 Javascript
bootstrap的常用组件和栅格式布局详解
May 02 Javascript
jQuery扇形定时器插件pietimer使用方法详解
Jul 18 jQuery
javascript数组定义的几种方法
Oct 06 Javascript
JS获取本地地址及天气的方法实例小结
May 10 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
全文搜索和替换
2006/10/09 PHP
Look And Say 序列php实现代码
2011/05/22 PHP
phpword插件导出word文件时中文乱码问题处理方案
2014/08/19 PHP
php带抄送和密件抄送的邮件发送方法
2015/03/20 PHP
PHP中的traits简单使用实例
2015/05/13 PHP
PHP中常见的密码处理方式和建议总结
2018/10/14 PHP
thinkPHP和onethink微信支付插件分享
2019/08/11 PHP
Thinkphp5.0框架的Db操作实例分析【连接、增删改查、链式操作等】
2019/10/11 PHP
StringTemplate遇见jQuery冲突的解决方法
2011/09/22 Javascript
SeaJS入门教程系列之SeaJS介绍(一)
2014/03/03 Javascript
JSON相关知识汇总
2015/07/03 Javascript
不依赖Flash和任何JS库实现文本复制与剪切附源码下载
2015/10/09 Javascript
jQuery绑定事件on()与弹窗的简要概述
2016/04/27 Javascript
实例讲解JavaScript中的this指向错误解决方法
2016/06/13 Javascript
Javascript类型系统之String字符串类型详解
2016/06/21 Javascript
详细谈谈javascript的对象
2016/07/31 Javascript
利用jquery给指定的table动态添加一行、删除一行的方法
2016/10/12 Javascript
详解javascript事件绑定使用方法
2016/10/20 Javascript
Angular 通过注入 $location 获取与修改当前页面URL的实例
2017/05/31 Javascript
详解ES6 Fetch API HTTP请求实用指南
2018/11/14 Javascript
javascript异步编程的六种方式总结
2019/05/17 Javascript
python实现网站微信登录的示例代码
2019/09/18 Python
python能做哪些生活有趣的事情
2020/09/09 Python
Python3爬虫ChromeDriver的安装实例
2021/02/06 Python
纯CSS3绘制打火机动画火焰效果
2016/07/18 HTML / CSS
莫斯科的韩国化妆品店:Sifo
2019/12/04 全球购物
高分子材料个人求职信范文
2013/09/25 职场文书
四年的大学生生活自我评价
2013/12/09 职场文书
股权转让协议书
2014/04/12 职场文书
多媒体教室标语
2014/06/26 职场文书
2016中考冲刺决心书
2015/09/22 职场文书
小学英语教师研修感悟
2015/11/18 职场文书
2016年学校党支部创先争优活动总结
2016/04/05 职场文书
Oracle设置DB、监听和EM开机启动的方法
2021/04/25 Oracle
为了顺利买到演唱会的票用Python制作了自动抢票的脚本
2021/10/16 Python
Win11 BitLocker 驱动器加密
2022/04/19 数码科技