首页 文章

使用纯HTML5 API实现React拖放

提问于
浏览
0

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

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

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?

1 回答

  • 0

    我想以下代码

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

    应该

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

    Notice the function name. 因为这是组件中调用的内容

    onDragEnd={this.onDragEnd}
    

    这只是问题的一部分 .

    您的 onDragEnd 函数正在尝试将拖动的对象附加到自身 . 伊克 . 那赢得了试图修改dom的努力 . 让反应修改它 .

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

    使其运作的一种方法

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

    github repo

    A 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>
        )
      }
    }
    

相关问题