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 相关文章推荐
分享一个asp.net pager分页控件
Jan 04 Javascript
JavaScript fontcolor方法入门实例(按照指定的颜色来显示字符串)
Oct 17 Javascript
jQuery实现contains方法不区分大小写的方法
Feb 13 Javascript
jQuery通过ajax快速批量提交表单数据
Oct 25 Javascript
JS封装通过className获取元素的函数示例
Dec 20 Javascript
css和js实现弹出登录居中界面完整代码
Nov 26 Javascript
在vue项目中安装使用Mint-UI的方法
Dec 27 Javascript
vue 之 .sync 修饰符示例详解
Apr 21 Javascript
原生JS实现简单的倒计时功能示例
Aug 30 Javascript
layui添加动态菜单与选项卡 AJAX请求的例子
Sep 25 Javascript
Vue+Java 通过websocket实现服务器与客户端双向通信操作
Sep 22 Javascript
Vue实现简单的留言板
Oct 23 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随机生成福彩双色球号码的2种方法
2013/02/04 PHP
php保存信息到当前Session的方法
2015/03/16 PHP
PHP7匿名类用法分析
2016/09/26 PHP
php实现头像上传预览功能
2017/04/27 PHP
jquery插件之easing 动态菜单
2010/08/21 Javascript
JS生成随机字符串的多种方法
2014/06/10 Javascript
原生JavaScript+LESS实现瀑布流
2014/12/12 Javascript
jquery实现邮箱自动填充提示功能
2015/11/17 Javascript
jQuery插件ajaxfileupload.js实现上传文件
2020/10/23 Javascript
为jQuery-easyui的tab组件添加右键菜单功能的简单实例
2016/10/10 Javascript
js实现图片切换(动画版)
2016/12/25 Javascript
jQuery实现圣诞节礼物动画案例解析
2016/12/25 Javascript
JS+Ajax实现百度智能搜索框
2017/08/04 Javascript
利用pm2部署多个node.js项目的配置教程
2017/10/22 Javascript
vue实现模态框的通用写法推荐
2018/02/26 Javascript
使用微信小程序开发弹出框应用实例详解
2018/10/18 Javascript
Vue+Vuex实现自动登录的知识点详解
2020/03/04 Javascript
JavaScript this关键字指向常用情况解析
2020/09/02 Javascript
Vue3为什么这么快
2020/09/23 Javascript
python中关于日期时间处理的问答集锦
2013/03/08 Python
python中sets模块的用法实例
2014/09/30 Python
Python实现提取谷歌音乐搜索结果的方法
2015/07/10 Python
Python正则表达式知识汇总
2017/09/22 Python
python2与python3共存问题的解决方法
2018/09/18 Python
利用Python将文本中的中英文分离方法
2018/10/31 Python
python利用百度AI实现文字识别功能
2018/11/27 Python
Python 装饰器@,对函数进行功能扩展操作示例【开闭原则】
2019/10/17 Python
Python自定义sorted排序实现方法详解
2020/09/18 Python
python 进制转换 int、bin、oct、hex的原理
2021/01/13 Python
Nike意大利官网:Nike.com IT
2020/01/19 全球购物
行政工作个人的自我评价
2014/02/13 职场文书
乡镇爱国卫生月活动总结
2014/06/25 职场文书
幼儿园教师安全责任书
2015/05/08 职场文书
合理化建议书范文
2015/09/14 职场文书
Html5通过数据流方式播放视频的实现
2021/04/27 HTML / CSS
SpringCloud之@FeignClient()注解的使用方式
2021/09/25 Java/Android