【问题标题】:React Drag and Drop with plain HTML5 API使用纯 HTML5 API 响应拖放
【发布时间】:2018-07-06 19:05:21
【问题描述】:

我正在尝试在不使用任何外部库的情况下通过拖放实现一个简单的网格,但是我遇到了一些问题。

首先,我似乎无法使用占位符;我不想相互交换项目,我想在用户将执行放置的项目之间创建某种空白空间。 其次,我只能将项目放在列表末尾。

Here is the fiddle

React + Plain HTML5 DnD API 的教程似乎并不多,但是在this tutorial 之后,我尝试通过在类之前声明它然后在 onDragOver 和 OnDragEnd 方法中使用它来设置一个占位符,但它一直对我大喊大叫

Failed to execute 'insertBefore' on 'Node': parameter 1 is not of type 'Node

此外,在本教程中,他将 onDragOver 设置为 ul 元素并且不处理任何 onDrop 事件,而我在我的项目上使用 onDragOver 并在网格容器上调用 onDrop。我这样做是对的还是我的 grid__container 应该只使用 onDragOver 而不是 onDrop?

【问题讨论】:

标签: html reactjs drag-and-drop


【解决方案1】:

我认为下面的代码

onDrop = (e) => {
    e.currentTarget.appendChild(this.state.dragged);
  }

应该是

onDragEnd = (e) => {
    e.currentTarget.appendChild(this.state.dragged);
  }

注意函数名。因为这是组件中调用的内容

onDragEnd={this.onDragEnd}

这只是问题的一部分。

您的onDragEnd 函数正在尝试将拖动的对象附加到自身。哎呀。那是行不通的,你不应该试图修改 dom。让 react 修改一下吧。

所以...react 正在显示 this.state.items 中的数组。在onDragEndonDragOver 中你需要更新this.state.items 以反映订单,然后让react 重新渲染并显示新订单。

让它发挥作用的方法

我的 github 页面上有一个工作示例,显示 HTML dnd 和 react-dnd 都在工作。

github repo

working example

component 尽善尽美。查看 src 文件夹中的 htmlList.js。

当拖动的项目越过另一个项目时,我采用了更新状态数组的方法。所以状态会在 dragOver 中更新。

这是组件的代码。注意,显示的项目数组存储在父组件中,请参见updateState 函数:

此外,还有一个shouldComponentUpdate,这样您只有在订单发生变化时才会重新渲染。

注意:我没有使用占位符,因为它不是必需的。当您将项目拖动到新位置时,整个列表会即时更新。

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import HtmlListItem from './HtmlListItem'
import './List.css'

export default class ListState extends Component {
  static propTypes = {
    data: PropTypes.arrayOf(
      PropTypes.shape({
        id: PropTypes.number.isRequired,
        name: PropTypes.string.isRequired,
        sortIndex: PropTypes.number.isRequired,
      })
    ).isRequired,

    handleDataChanged: PropTypes.func.isRequired,
  }
  static defaultProps = {
    data: {},
  }

  constructor(props) {
    super(props)
    this.state = {
      draggedOverId: undefined,
      beingDragged: undefined,
    }

    this.updateState = this.updateState.bind(this)
    this.dragStart = this.dragStart.bind(this)
    this.dragOver = this.dragOver.bind(this)
    this.dragEnd = this.dragEnd.bind(this)
  }

  shouldComponentUpdate(nextProps, nextState) {
    // only update when the item being hovered changes,
    if (nextState.draggedOverId === this.state.draggedOverId) return false
    return true
  }

  updateState(houses, draggedOverId) {
    this.setState({ draggedOverId: draggedOverId, beingDragged: draggedOverId })

    // update the sortIndex to show the new order
    houses.forEach((house, i) => {
      house.sortIndex = i
    })

    // Tell the parent there is a new order
    this.props.handleDataChanged(houses)
  }

  dragStart(e) {
    // Update our state with the item that is being dragged
    this.setState({ beingDragged: Number(e.target.dataset.id) })
    e.dataTransfer.effectAllowed = 'move'
  }

  dragOver(e) {
    e.preventDefault()

    // ignore when dragging over the list container
    if (e.target.className === 'list') return

    let from = this.state.beingDragged
    let to = Number(e.target.dataset.id)
    this.setState({ draggedOverId: to })

    // reorder the array with the current hover position
    let items = this.props.data
    items.splice(to, 0, items.splice(from, 1)[0])

    this.updateState(items, to)
  }

  dragEnd() {
    // Update state to force removal of the class used for highlighting
    this.updateState(this.props.data, undefined)
  }

  render() {
    const { data } = this.props
    const { draggedOverId } = this.state

    const HtmllistItems = data.map((house, i) => {
      // highlight the new position
      let dragClass = i === draggedOverId ? 'listitem-over' : ''

      return (
        <HtmlListItem
          key={house.id}
          dataId={i}
          className={dragClass}
          text={house.name}
          dragStart={this.dragStart}
          dragEnd={this.dragEnd}
        />
      )
    })

    return (
      <ul className="list" onDragOver={this.dragOver}>
        {HtmllistItems}
      </ul>
    )
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多