简单的拖放操作,无需外部库即可进行排序

时间:2019-07-17 09:37:32

标签: reactjs drag-and-drop

我想通过排序实现元素的拖放操作,并且我不想使用任何外部库。

将有2个容器,我想对一个容器中的元素进行排序,然后在两个容器之间拖放。有什么建议吗?

我尝试了HTML5和其他方法,但没有成功

3 个答案:

答案 0 :(得分:0)

enter image description here

在上面的屏幕截图中,我想将元素从显示的位置拖放到隐藏的位置,反之亦然,也要在“显示的”行中对元素进行排序

答案 1 :(得分:0)

您可以将onDroponDrag事件分配给div。您可以将每个组件固定在数组中,拖动时可以将其从and数组中删除,拖放时可以将该项目添加到array中。之后,您可以按array.sort()

对数组进行排序
<div onDrag={this.handleDrag()} onDrop={thishandleDrop()}>

handleDrag = () => {
    //remove your item in array here
}

handleDrag = () => {
        //add your item to array here
    }

答案 2 :(得分:0)

/**
 * Displays Dialog for Table show/hide columns
 * @default {string} submitLabel, cancelLabel
 * @default {bool} open
 * @default {array} suggestions
 */

import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import SettingsIcon from "@material-ui/icons/Settings";
import IconButton from "@material-ui/core/IconButton";
import { theme } from "../../../../utilities/theme-default";
import HLTooltip from "../../../atoms/ToolTip";
import HLDialog from "../../../grouped/Dialog";
import HLSaveSettings from "../SaveTableSettings";
import HLTypography from "../../../atoms/Typography";
import HLChip from "@material-ui/core/Chip";
import * as colors from "../../../../utilities/color";
import Draggable from "react-draggable";

export const styles = () => ({
  tableAction: {
    width: "100%",
    marginTop: `${theme.spacing.unit}px`
  },
  container: {
    display: "flex"
  },
  title: {
    flex: "0 0 auto"
  },
  section: {
    border: `1px solid ${colors.neutralDark["120"]}`,
    marginTop: `${theme.spacing.unit * 3}px`,
    padding: `${theme.spacing.unit}px 0 ${theme.spacing.unit * 3}px ${theme
      .spacing.unit * 6}px`,
    display: "flex"
  },
  chipTextStyle: {
    marginTop: `${theme.spacing.unit * 4}px`
  },
  chipStyle: {
    padding: `${theme.spacing.unit * 3}px`,
    marginTop: `${theme.spacing.unit}px`
  },
  dialogStyle: {
    width: "500px"
  },
  defaultSection: {
    marginTop: `${theme.spacing.unit * 2}px`
  }
});

/**
 * state component which handles table show/hide columns
 */
export class HLShowHide extends React.Component {
  state = {
    open: false,
    headers: this.props.headers
  };

  /**
   * function to display dialog for show/hide opetations
   */
  dialogToggle = () => {
    this.setState({
      open: !this.state.open
    });
  };

  onStart() {
    this.setState({ activeDrags: this.state.activeDrags + 1 });
  }

  onStop() {
    this.setState({ activeDrags: this.state.activeDrags - 1 });
  }

  onDragStart = (e, sectionIndex, index) => {
    e.stopPropagation();
    this.draggedItem = this.state.headers.sections[sectionIndex].items[index];
    this.dragItemSection = sectionIndex;
    this.dragItemIndex = index;
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/html", e.target.parentNode);
    e.dataTransfer.setDragImage(e.target.parentNode, 20, 20);
  };

  onDragOver = (sectionIndex, index) => {
    const draggedOverItem = this.state.headers.sections[sectionIndex].items[
      index
    ];

    // if the item is dragged over itself, ignore
    if (this.draggedItem === draggedOverItem) {
      return;
    }
    if (this.dragItemSection !== sectionIndex) {
      var otherItems = this.state.headers.sections[this.dragItemSection].items;
      otherItems.splice(this.dragItemIndex, 1);
    }
    // filter out the currently dragged item
    let items = this.state.headers.sections[sectionIndex].items.filter(
      item => item !== this.draggedItem
    );

    // add the dragged item after the dragged over item
    items.splice(index, 0, this.draggedItem);
    const sections = this.state.headers.sections;
    sections[sectionIndex].items = items;
    sections[this.dragItemSection].items = otherItems;
    this.setState({ headers: { ...this.state.headers, sections } });
  };

  onDragOverSection = sectionIndex => {
    if (this.state.headers.sections[sectionIndex].length === 0) {
      var otherItems = this.state.headers.sections[this.dragItemSection].items;
      otherItems.splice(this.dragItemIndex, 1);
      let items = this.state.headers.sections[sectionIndex].items;
      items.push(this.draggedItem);
      const sections = this.state.headers.sections;
      sections[this.dragItemSection].items = otherItems;
      sections[sectionIndex].items = items;
      this.setState({ headers: { ...this.state.headers, sections } });
    }
  };

  onDragEnd = () => {
    this.draggedIdx = null;
  };

  render() {
    const { classes, submitLabel, cancelLabel } = this.props;
    const { open, headers } = this.state;
    const dragHandlers = {
      onStart: this.onStart.bind(this),
      onStop: this.onStop.bind(this)
    };

    const dialogBody = (
      <div className={classes.dialogStyle}>
        {headers.sections.map((section, sectionIndex) => (
          <div className={classes.section}>
            <span className={classes.chipTextStyle}>
              <HLTypography
                variant={
                  theme.palette.tableConstant.showHideColumn.sections.variant
                }
                color={
                  theme.palette.tableConstant.showHideColumn.sections.color
                }
              >
                {section.label}
              </HLTypography>
            </span>
            <span onDragOver={() => this.onDragOverSection(sectionIndex)}>
              {section.items.map((item, itemIndex) => (
                <div
                  className={classes.chipStyle}
                  key={item.value}
                  data-id={`${itemIndex}_${sectionIndex}`}
                  onDragOver={() => this.onDragOver(sectionIndex, itemIndex)}
                >
                  <Draggable
                    onDrag={this.handleDrag.bind(this)}
                    {...dragHandlers}
                  >
                    <HLChip label={item.label} />
                  </Draggable>
                </div>
              ))}
            </span>
          </div>
        ))}
        <div className={classes.defaultSection}>
          <HLSaveSettings
            defaultLabel={headers.defaultLabel}
            isDefault={headers.isDefault}
          />
        </div>
      </div>
    );
    return (
      <React.Fragment>
        {open && (
          <div className={classes.container}>
            <div className={classes.tableAction}>
              <HLDialog
                open={open}
                submitLabel={submitLabel}
                cancelLabel={cancelLabel}
                bodyText={dialogBody}
                maxWidth="xl"
                onSubmit={() => {}}
                onCancel={() => {
                  this.dialogToggle();
                }}
              />
            </div>
          </div>
        )}
        {!open && (
          <React.Fragment>
            <HLTooltip title="Settings" placement="top">
              <IconButton aria-label="Settings">
                <SettingsIcon onClick={this.dialogToggle} />
              </IconButton>
            </HLTooltip>
          </React.Fragment>
        )}
      </React.Fragment>
    );
  }
}

HLShowHide.propTypes = {
  classes: PropTypes.object,
  headers: PropTypes.arrayOf().isRequired,
  open: PropTypes.bool,
  submitLabel: PropTypes.string,
  cancelLabel: PropTypes.string
};

HLShowHide.defaultProps = {
  open: false,
  submitLabel: "Set",
  cancelLabel: "Cancel"
};

export default withStyles(styles)(HLShowHide);

我尝试过的代码