初心始现 發表於 2020-11-11 11:14:00

使用react 实现拖拽功能

<h3>一、关于拖动</h3>
<p style="margin-left: 30px">图片默认可以拖动,其他元素的拖动效果同图片。正常的 div 是不能被拖动的,鼠标点击选择后移动没有效果,需要加&nbsp;<span style="text-decoration: underline">draggable="true"&nbsp;</span>使得元素可以被拖动。</p>
<h3>二、拖拽相关的几个事件</h3>
<p style="margin-left: 30px">被拖拽元素的事件:ondragstart,ondragend&nbsp;</p>
<p style="margin-left: 30px">放置元素的事件:ondragenter、ondragover、ondragleave、ondrop&nbsp;</p>
<p style="margin-left: 30px">顾名思义,不需要解释。</p>
<p style="margin-left: 30px">需要注意是&nbsp;ondragover&nbsp;的默认事件&nbsp;Reset the current drag operation to "none".&nbsp;所以想让一个元素可放置,需要重写&nbsp;ondragover&nbsp;</p>
<div class="cnblogs_code" style="margin-left: 30px">
<pre>element.ondragover = event =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    event.preventDefault();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ...</span>
}</pre>
</div>
<p style="margin-left: 30px">当一个元素是可放置的,拖拽经过时鼠标会变成加号(cursor: copy;)<img src="https://img2020.cnblogs.com/blog/1895520/202011/1895520-20201111110222481-607359219.png" alt="" width="14" height="13" loading="lazy"></p>
<p style="margin-left: 30px">&nbsp;有一个对象&nbsp;dataTransfer&nbsp;可以用来存储拖拽数据。</p>
<div class="cnblogs_code" style="margin-left: 30px">
<pre>dragEle.ondragstart = e =&gt; e.dataTransfer.setData('item', e.target.id);</pre>
</div>
<p style="margin-left: 30px">拖拽开始时触发,把被拖拽元素的 id 存入&nbsp;&nbsp;<span class="cnblogs_code">e.dataTransfer&nbsp;</span></p>
<p style="margin-left: 30px">然后在&nbsp;ondrop 的时候 可以获取到这个值 (ondragenter、ondragover、ondragleave 获取不到...)</p>
<div class="cnblogs_code" style="margin-left: 30px">
<pre>putEle.ondrop = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(e) {
   let id </span>= e.dataTransfer.getData('item'<span style="color: rgba(0, 0, 0, 1)">);
   </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ...</span>
}</pre>
</div>
<h3>&nbsp;三、react中使用代码演示 [点击查看演示]</h3>
<p style="margin-left: 30px">&nbsp;</p>
<div class="cnblogs_code" style="margin-left: 30px">
<pre>&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
      &lt;meta charset="utf-8"&gt;
      &lt;title&gt;&lt;/title&gt;
      &lt;script src="https://unpkg.com/react@16/umd/react.development.js"&gt;&lt;/script&gt;
      &lt;script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"&gt;&lt;/script&gt;
      &lt;script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"&gt;&lt;/script&gt;
      &lt;style&gt;<span style="color: rgba(0, 0, 0, 1)">
            .item {
                border: 1px solid #1da921;
                width: 180px;
                border</span>-<span style="color: rgba(0, 0, 0, 1)">radius: 5px;
                box</span>-shadow: 0 0 5px 0<span style="color: rgba(0, 0, 0, 1)"> #b3b3b3;
                margin: 5px auto;
                background: #fff;
            }
            .item.active {
                border</span>-<span style="color: rgba(0, 0, 0, 1)">style: dashed;
            }
            .item</span>-<span style="color: rgba(0, 0, 0, 1)">header {
                font</span>-<span style="color: rgba(0, 0, 0, 1)">size: 12px;
                color: #9e9e9e;
                padding: 3px 5px;
            }
            .item</span>-<span style="color: rgba(0, 0, 0, 1)">main {
                padding: 5px;
                font</span>-<span style="color: rgba(0, 0, 0, 1)">size: 14px;
                color: #</span>424242<span style="color: rgba(0, 0, 0, 1)">;
                height: 36px;
                overflow: hidden;
                text</span>-<span style="color: rgba(0, 0, 0, 1)">overflow: ellipsis;
                display: </span>-webkit-<span style="color: rgba(0, 0, 0, 1)">box;
                </span>-webkit-box-<span style="color: rgba(0, 0, 0, 1)">orient: vertical;
                </span>-webkit-line-clamp: 2<span style="color: rgba(0, 0, 0, 1)">;
            }
            .item</span>-header-<span style="color: rgba(0, 0, 0, 1)">point {
                background: #ccc;
                </span><span style="color: rgba(0, 0, 255, 1)">float</span><span style="color: rgba(0, 0, 0, 1)">: right;
                padding: </span>0<span style="color: rgba(0, 0, 0, 1)"> 4px;
                min</span>-<span style="color: rgba(0, 0, 0, 1)">width: 10px;
                text</span>-<span style="color: rgba(0, 0, 0, 1)">align: center;
                color: #fff;
                border</span>-radius: 50%<span style="color: rgba(0, 0, 0, 1)">;
            }
            .col {
                border: 1px solid #d2d2d2;
                flex</span>-grow: 1<span style="color: rgba(0, 0, 0, 1)">;
                width: 180px;
                height: </span>100%<span style="color: rgba(0, 0, 0, 1)">;
                margin: </span>0<span style="color: rgba(0, 0, 0, 1)"> 2px;
                background: #eee;
                flex</span>-grow: 1<span style="color: rgba(0, 0, 0, 1)">;
                display: flex;
                flex</span>-<span style="color: rgba(0, 0, 0, 1)">direction: column;
            }
            .col</span>-<span style="color: rgba(0, 0, 0, 1)">header {
                height: 40px;
                line</span>-<span style="color: rgba(0, 0, 0, 1)">height: 40px;
                background: #1DA921;
                color: #fff;
                text</span>-<span style="color: rgba(0, 0, 0, 1)">align: center;
            }
            .col</span>-<span style="color: rgba(0, 0, 0, 1)">main {
                overflow: auto;
                flex</span>-grow: 1<span style="color: rgba(0, 0, 0, 1)">;
            }
            .col</span>-<span style="color: rgba(0, 0, 0, 1)">main.active {
                background: #00ad23;
                opacity: </span>0.1<span style="color: rgba(0, 0, 0, 1)">;
            }
            .task</span>-<span style="color: rgba(0, 0, 0, 1)">wrapper {
                display: flex;
                height: 400px;
                width: 700px;
            }
      </span>&lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;div id="app"&gt;&lt;/div&gt;
      &lt;script type="text/babel"&gt;<span style="color: rgba(0, 0, 0, 1)">
            const STATUS_TODO </span>= 'STATUS_TODO'<span style="color: rgba(0, 0, 0, 1)">;
            const STATUS_DOING </span>= 'STATUS_DOING'<span style="color: rgba(0, 0, 0, 1)">;
            const STATUS_DONE </span>= 'STATUS_DONE'<span style="color: rgba(0, 0, 0, 1)">;
            
            const STATUS_CODE </span>=<span style="color: rgba(0, 0, 0, 1)"> {
                STATUS_TODO: </span>'待处理'<span style="color: rgba(0, 0, 0, 1)">,
                STATUS_DOING: </span>'进行中'<span style="color: rgba(0, 0, 0, 1)">,
                STATUS_DONE: </span>'已完成'<span style="color: rgba(0, 0, 0, 1)">
            }
            let tasks </span>=<span style="color: rgba(0, 0, 0, 1)"> [{
                id: </span>0<span style="color: rgba(0, 0, 0, 1)">,
                status: STATUS_TODO,
                title: </span>'每周七天阅读五次,每次阅读完要做100字的读书笔记'<span style="color: rgba(0, 0, 0, 1)">,
                username: </span>'小夏'<span style="color: rgba(0, 0, 0, 1)">,
                point: </span>10<span style="color: rgba(0, 0, 0, 1)">
            }, {
                id: </span>1<span style="color: rgba(0, 0, 0, 1)">,
                status: STATUS_TODO,
                title: </span>'每周七天健身4次,每次健身时间需要大于20分钟'<span style="color: rgba(0, 0, 0, 1)">,
                username: </span>'橘子🍊'<span style="color: rgba(0, 0, 0, 1)">,
                point: </span>5<span style="color: rgba(0, 0, 0, 1)">
            }, {
                id: </span>2<span style="color: rgba(0, 0, 0, 1)">,
                status: STATUS_TODO,
                title: </span>'单词*100'<span style="color: rgba(0, 0, 0, 1)">,
                username: </span>'┑( ̄Д  ̄)┍'<span style="color: rgba(0, 0, 0, 1)">,
                point: </span>2<span style="color: rgba(0, 0, 0, 1)">
            }, {
                id: </span>3<span style="color: rgba(0, 0, 0, 1)">,
                status: STATUS_TODO,
                title: </span>'单词*150'<span style="color: rgba(0, 0, 0, 1)">,
                username: </span>'┑( ̄Д  ̄)┍'<span style="color: rgba(0, 0, 0, 1)">,
                point: </span>2<span style="color: rgba(0, 0, 0, 1)">
            }, {
                id: </span>4<span style="color: rgba(0, 0, 0, 1)">,
                status: STATUS_TODO,
                title: </span>'单词*200'<span style="color: rgba(0, 0, 0, 1)">,
                username: </span>'┑( ̄Д  ̄)┍'<span style="color: rgba(0, 0, 0, 1)">,
                point: </span>2<span style="color: rgba(0, 0, 0, 1)">
            }, {
                id: </span>5<span style="color: rgba(0, 0, 0, 1)">,
                status: STATUS_TODO,
                title: </span>'单词*250'<span style="color: rgba(0, 0, 0, 1)">,
                username: </span>'┑( ̄Д  ̄)┍'<span style="color: rgba(0, 0, 0, 1)">,
                point: </span>2<span style="color: rgba(0, 0, 0, 1)">
            }]
            
            class TaskItem extends React.Component {
                handleDragStart </span>= (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  </span><span style="color: rgba(0, 0, 255, 1)">this</span>.props.onDragStart(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props.id);
                }
                render() {
                  let { id, title, point, username, active, onDragEnd } </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props;
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                        </span>&lt;<span style="color: rgba(0, 0, 0, 1)">div
                            onDragStart</span>={<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.handleDragStart}
                            onDragEnd</span>=<span style="color: rgba(0, 0, 0, 1)">{onDragEnd}
                            id</span>={`item-<span style="color: rgba(0, 0, 0, 1)">${id}`}
                            className</span>={'item' + (active ? ' active' : ''<span style="color: rgba(0, 0, 0, 1)">)}
                            draggable</span>="true"
                        &gt;
                            &lt;header className="item-header"&gt;
                              &lt;span className="item-header-username"&gt;{username}&lt;/span&gt;
                              &lt;span className="item-header-point"&gt;{point}&lt;/span&gt;
                            &lt;/header&gt;
                            &lt;main className="item-main"&gt;{title}&lt;/main&gt;
                        &lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">                  );
                }
            }
            
            class TaskCol extends React.Component {
                state </span>=<span style="color: rgba(0, 0, 0, 1)"> {
                  </span><span style="color: rgba(0, 0, 255, 1)">in</span>: <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
                }
                handleDragEnter </span>= (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  e.preventDefault();
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props.canDragIn) {
                        </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setState({
                            </span><span style="color: rgba(0, 0, 255, 1)">in</span>: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
                        })
                  }
                }
                handleDragLeave </span>= (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  e.preventDefault();
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props.canDragIn) {
                        </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setState({
                            </span><span style="color: rgba(0, 0, 255, 1)">in</span>: <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
                        })
                  }
                }
                handleDrop </span>= (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  e.preventDefault();
                  </span><span style="color: rgba(0, 0, 255, 1)">this</span>.props.dragTo(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props.status);
                  </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setState({
                        </span><span style="color: rgba(0, 0, 255, 1)">in</span>: <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
                  })
                }
                render() {
                  let { status, children } </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props;
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                        </span>&lt;<span style="color: rgba(0, 0, 0, 1)">div
                            id</span>={`col-<span style="color: rgba(0, 0, 0, 1)">${status}`}
                            className</span>={'col'<span style="color: rgba(0, 0, 0, 1)">}
                            onDragEnter</span>={<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.handleDragEnter}
                            onDragLeave</span>={<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.handleDragLeave}
                            onDragOver</span>={<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.handleDragEnter}
                            onDrop</span>={<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.handleDrop}
                            draggable</span>="true"
                        &gt;
                            &lt;header className="col-header"&gt;<span style="color: rgba(0, 0, 0, 1)">
                              {STATUS_CODE}
                            </span>&lt;/header&gt;
                            &lt;main className={'col-main' + (<span style="color: rgba(0, 0, 255, 1)">this</span>.state.<span style="color: rgba(0, 0, 255, 1)">in</span> ? ' active' : '')}&gt;<span style="color: rgba(0, 0, 0, 1)">
                              {children}
                            </span>&lt;/main&gt;
                        &lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">                  );
                }
            }
            
            class App extends React.Component {
                state </span>=<span style="color: rgba(0, 0, 0, 1)"> {
                  tasks: tasks,
                  activeId: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
                }
                </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
               * 传入被拖拽任务项的 id
               </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
                onDragStart </span>= (id) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setState({
                        activeId: id
                  })
                }
               
                dragTo </span>= (status) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  let { tasks,activeId} </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.state;
                  let task </span>=<span style="color: rgba(0, 0, 0, 1)"> tasks;
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span> (task.status !==<span style="color: rgba(0, 0, 0, 1)"> status) {
                        task.status </span>=<span style="color: rgba(0, 0, 0, 1)"> status;
                        </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setState({
                            tasks: tasks
                        })
                  }
                  </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.cancelSelect();
                }
               
                cancelSelect </span>= () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setState({
                        activeId: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
                  })
                }
               
                render() {
                  let { tasks, activeId } </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.state;
                  let { onDragStart, onDragEnd, cancelSelect } </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                        </span>&lt;div className="task-wrapper"&gt;<span style="color: rgba(0, 0, 0, 1)">
                            {
                              Object.keys(STATUS_CODE).map(status </span>=&gt;
                                    &lt;<span style="color: rgba(0, 0, 0, 1)">TaskCol
                                        status</span>=<span style="color: rgba(0, 0, 0, 1)">{status}
                                        key</span>=<span style="color: rgba(0, 0, 0, 1)">{status}
                                        dragTo</span>={<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.dragTo}
                                        canDragIn</span>={activeId != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; tasks.status !== status}&gt;<span style="color: rgba(0, 0, 0, 1)">
                                        { tasks.filter(t </span>=&gt; t.status === status).map(t =&gt;
                                          &lt;<span style="color: rgba(0, 0, 0, 1)">TaskItem
                                                key</span>=<span style="color: rgba(0, 0, 0, 1)">{t.id}
                                                active</span>={t.id ===<span style="color: rgba(0, 0, 0, 1)"> activeId}
                                                id</span>=<span style="color: rgba(0, 0, 0, 1)">{t.id}
                                                title</span>=<span style="color: rgba(0, 0, 0, 1)">{t.title}
                                                point</span>=<span style="color: rgba(0, 0, 0, 1)">{t.point}
                                                username</span>=<span style="color: rgba(0, 0, 0, 1)">{t.username}
                                                onDragStart</span>=<span style="color: rgba(0, 0, 0, 1)">{onDragStart}
                                                onDragEnd</span>=<span style="color: rgba(0, 0, 0, 1)">{cancelSelect}
                                          </span>/&gt;)
<span style="color: rgba(0, 0, 0, 1)">                                        }
                                    </span>&lt;/TaskCol&gt;
<span style="color: rgba(0, 0, 0, 1)">                              )
                            }
                        </span>&lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">                  )
                }
            }
            
            ReactDOM.render(
                </span>&lt;App /&gt;,
                document.getElementById('app'<span style="color: rgba(0, 0, 0, 1)">)
            );
      </span>&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<h3>四、效果</h3>
<p style="margin-left: 30px"><img src="https://img2020.cnblogs.com/blog/1895520/202011/1895520-20201111111350101-388729124.png" alt="" loading="lazy"></p>
<h3>四、演示地址:</h3>
<p>  查看演示</p>
<p>&nbsp;</p>
<h3>五、原文来源</h3>
<p>  【我不吃饼干呀】&nbsp;的博客 文章</p><br><br>
来源:https://www.cnblogs.com/art-poet/p/13957728.html
頁: [1]
查看完整版本: 使用react 实现拖拽功能