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 相关文章推荐
用ADODB.Stream转换
Jan 22 Javascript
jquery入门——事件机制之事件中的冒泡现象示例解释
Sep 12 Javascript
浅析JS刷新框架中的其他页面 &amp;&amp; JS刷新窗口方法汇总
Jul 08 Javascript
基于jQuery实现表单提交验证
Nov 24 Javascript
jQuery 弹出层插件(推荐)
May 24 Javascript
jquery使用on绑定a标签无效 只能用live解决
Jun 02 Javascript
javascript 内置对象及常见API详细介绍
Nov 01 Javascript
javascript中的try catch异常捕获机制用法分析
Dec 14 Javascript
javascript 中null和undefined区分和比较
Apr 19 Javascript
Vue全家桶实践项目总结(推荐)
Nov 04 Javascript
vue.js 实现a标签href里添加参数
Nov 12 Javascript
理解JavaScript中的对象
Aug 25 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
将RTF格式的文件转成HTML并在网页中显示的代码
2006/10/09 PHP
CodeIgniter框架提示Disallowed Key Characters的解决办法
2014/04/21 PHP
php中二维数组排序问题方法详解
2015/08/28 PHP
php数据库的增删改查 php与javascript之间的交互
2017/08/31 PHP
JavaScript 实现模态对话框 源代码大全
2009/05/02 Javascript
事件模型在各浏览器中存在差异
2010/10/20 Javascript
jQuery实现类似标签风格的导航菜单效果代码
2015/08/25 Javascript
jQuery实现的超酷苹果风格图标滑出菜单效果代码
2015/09/16 Javascript
详解Node.Js如何处理post数据
2016/09/19 Javascript
WdatePicker.js时间日期插件的使用方法
2017/07/26 Javascript
在Vue组件上动态添加和删除属性方法
2018/02/23 Javascript
node.js实现带进度条的多文件上传
2020/03/27 Javascript
在Vue.js中使用TypeScript的方法
2020/03/19 Javascript
js实现微信聊天界面
2020/08/09 Javascript
js实现表格数据搜索
2020/08/09 Javascript
[01:01:41]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma BO3 第二场 1月31日
2021/03/11 DOTA
Python实现Tab自动补全和历史命令管理的方法
2015/03/12 Python
python妹子图简单爬虫实例
2015/07/07 Python
python 中字典嵌套列表的方法
2018/07/03 Python
python2和python3应该学哪个(python3.6与python3.7的选择)
2019/10/01 Python
python filecmp.dircmp实现递归比对两个目录的方法
2020/05/22 Python
魅力惠奢品线上平台:MEI.COM
2016/11/29 全球购物
纪伊国屋新加坡网上书店:Kinokuniya新加坡
2017/12/29 全球购物
Shop Apotheke瑞士:您的健康与美容网上商店
2019/10/09 全球购物
ORLY官网:美国专业美甲一线品牌
2019/12/11 全球购物
在DELPHI中调用存储过程和使用内嵌SQL哪种方式更好
2016/11/22 面试题
信息服务专业毕业生求职信
2014/03/02 职场文书
企业文化演讲稿
2014/05/20 职场文书
地方白酒代理协议书
2014/10/25 职场文书
党的群众路线学习笔记
2014/11/06 职场文书
工商局个人工作总结
2015/03/03 职场文书
员工聘用合同范本
2015/09/21 职场文书
2016年“5.12”护士节慰问信
2015/11/30 职场文书
2016年教师党员承诺书范文
2016/03/24 职场文书
css 中多种边框的实现小窍门
2021/04/07 HTML / CSS
ECharts transform数据转换和dataZoom在项目中使用
2022/12/24 Javascript