如何在 React 中实现拖放行为



我正在尝试使用 React 和 react-beautiful-dnd 库实现拖放行为。

我想使用 react-dropzone 库选择一些图像,选择图像后,我在屏幕右侧显示缩略图,之后我希望能够将其中一个缩略图拖到左侧并将其拖放到其中一个容器中。

我的代码如下:

import React, { Component } from "react";
import ReactDOM from "react-dom";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import Dropzone from "react-dropzone";
import { Animated } from "react-animated-css";
import { orderBy } from "lodash";
import UUID from "uuid";
import "./styles.css";
const animationIn = "fadeInDown";
const animationOut = "fadeOutUp";
const animationDuration = 400; // in ms
const pictureTypes = [
  {
    title: "3/4 front left",
    imageOverlay: "https://via.placeholder.com/100",
    item: "front-left",
    mandatory: true,
    image: null,
    priority: 1
  },
  {
    title: "3/4 rear right",
    imageOverlay: "https://via.placeholder.com/100",
    item: "rear-right",
    mandatory: true,
    image: null,
    priority: 2
  },
  {
    title: "Inside door right",
    imageOverlay: "https://via.placeholder.com/100",
    item: "front-door-right-i",
    mandatory: true,
    image: null,
    priority: 3
  }
];
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      files: [],
      pictureTypes: pictureTypes
    };
    this.onDragEnd = this.onDragEnd.bind(this);
  }
  onDragEnd(result) {
    debugger;
    // dropped outside the list
    if (!result.destination) {
      return;
    }
  }
  addFilesToState(files) {
    let files_with_preview = [];
    files.map(file => {
      file["preview"] = URL.createObjectURL(file);
      files_with_preview.push(file);
      this.setState({ [`visibleAnimate${file.path}`]: true });
    });
    const new_files = [...this.state.files, ...files_with_preview];
    this.setState({ files: new_files });
  }
  renderPreviews(files) {
    if (files.length < 1)
      return <div>Drag and drop some files to see them here.</div>;
    return (
      <div style={{ display: "flex", flexDirection: "column" }}>
        <div>Chosen pictures</div>
        <div style={{ display: "flex", flexDirection: "row" }}>
          {files.map((file, index) => {
            return (
              <Draggable key={UUID.v4()} draggableId={UUID.v4()} index={index}>
                {provided => (
                  <div
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    <img
                      src={file.preview}
                      alt={file.path}
                      style={{ width: 80 }}
                    />
                  </div>
                )}
              </Draggable>
            );
          })}
        </div>
      </div>
    );
  }
  handlePictureTypesDrop(file, pictureType) {
    const file_blob = URL.createObjectURL(file);
    const updated_picture_type = {
      ...this.state.pictureTypes.find(pt => pt.item === pictureType.item),
      image: file_blob
    };
    const updated_picture_types = [
      ...this.state.pictureTypes.filter(pt => pt.item !== pictureType.item),
      updated_picture_type
    ];
    let new_picture_types = [...updated_picture_types];
    this.setState({ pictureTypes: new_picture_types });
  }
  renderPictureTypes() {
    const { allowed_types } = this.props;
    const { pictureTypes } = this.state;
    const self = this;
    return orderBy(pictureTypes, "priority").map(pt => {
      return (
        <div style={{ width: "25%", marginRight: 5 }}>
          <Dropzone
            onDrop={files => self.handlePictureTypesDrop(files[0], pt)}
            accept={allowed_types}
            multiple={false}
          >
            {({ getRootProps, getInputProps }) => (
              <div {...getRootProps()}>
                <input {...getInputProps()} />
                <div className="picture-types-wrapper">
                  <div>
                    <img
                      src={pt.image !== null ? pt.image : pt.imageOverlay}
                      alt={pt.title}
                    />
                  </div>
                  <div style={{ fontSize: "0.65rem" }}>{pt.title}</div>
                </div>
              </div>
            )}
          </Dropzone>
        </div>
      );
    });
  }
  // Normally you would want to split things out into separate components.
  // But in this example everything is just done in one place for simplicity
  render() {
    const { files } = this.state;
    const self = this;
    return (
      <DragDropContext onDragEnd={this.onDragEnd}>
        <Droppable droppableId="droppable">
          {provided => (
            <div
              key="droppable"
              {...provided.droppableProps}
              ref={provided.innerRef}
            >
              <Dropzone
                onDrop={files => self.addFilesToState(files)}
                accept="image/jpeg, image/png"
              >
                {({ getRootProps, getInputProps }) => (
                  <section className="drag-drop-section">
                    <div {...getRootProps()}>
                      <input {...getInputProps()} />
                      <p className="drag-drop-text">
                        Drag 'n' drop some files here, or click to select files
                      </p>
                    </div>
                  </section>
                )}
              </Dropzone>
              <div
                style={{ display: "flex", flexDirection: "row", marginTop: 10 }}
              >
                <div style={{ display: "flex", flexDirection: "row" }}>
                  {self.renderPictureTypes()}
                </div>
                <div className="flex w-1/2 pl-2">
                  {self.renderPreviews(files)}
                </div>
              </div>
              {provided.placeholder}
            </div>
          )}
        </Droppable>
      </DragDropContext>
    );
  }
}
// Put the thing into the DOM!
ReactDOM.render(<App />, document.getElementById("root"));

下面是代码沙盒上的示例代码。

照片已成功添加到我渲染缩略图的右侧,但我无法将其中一个拖到左侧。

知道如何解决吗?

><Draggable>应该在<Droppable>

<Draggable />组件可以拖放到<Droppable />s上。<Draggable />必须始终包含在<Droppable />中。可以在其主<Droppable />内对<Draggable />重新排序或移动到另一个<Droppable />。这是可能的,因为<Droppable />可以自由控制它允许掉落在其上的内容。看这里

最新更新