React-dnd: Eine Möglichkeit, nach draußen zu iframe zu ziehen

Erstellt am 1. Aug. 2019  ·  6Kommentare  ·  Quelle: react-dnd/react-dnd

Bezieht sich Ihre Funktionsanfrage auf ein Problem?
Reagieren Sie auf Grenzen, die per Drag-and-Drop innerhalb eines einzelnen HTML-Dokuments ausgeführt werden. Irgendwie müssen wir etwas nach außen in einen iframe nach innen ziehen.

Beschreiben Sie die gewünschte Lösung
Ich finde, dass dnd HTML5backend nur Drag-Callbacks im Fenster auslöst. Wenn wir also die Komponenten im Inneren iframe machen auslösen können diejenigen callback.And React.createPortal make Komponenten innerhalb iframe gleichen DndProvider haben mit outside.It arbeitet, zum Glück. Aber ich mache mir Sorgen um ein Problem, das ich nicht bemerkt habe. Und der Code ist mit HTML5Backend nicht so bequem.

import React, {
  useRef,
  useEffect,
  useContext,
  forwardRef,
} from 'react';
import classnames from 'classnames';
import { DndContext } from 'react-dnd';

// Frame base on createPortal inside iframe dom.
import Frame from 'react-frame-component';

const events = [
  ['dragstart', 'handleTopDragStart', false],
  ['dragstart', 'handleTopDragStartCapture', true],
  ['dragend', 'handleTopDragEndCapture', true],
  ['dragenter', 'handleTopDragEnter', false],
  ['dragenter', 'handleTopDragEnterCapture', true],
  ['dragleave', 'handleTopDragLeaveCapture', true],
  ['dragover', 'handleTopDragOver', false],
  ['dragover', 'handleTopDragOverCapture', true],
  ['drop', 'handleTopDrop', false],
  ['drop', 'handleTopDropCapture', true],
];

export const DndFrame = forwardRef((props = {}, ref) => {
  const container = useRef(null);
  const dndValue = useContext(DndContext) || {};

  const { dragDropManager: { backend = {} } = {} } = dndValue;
  const { children, className, containerProps = {}, ...others } = props;

  const cls = classnames({
    'dnd-frame': true,
    [className]: !!className,
  });

  useEffect(() => {
    const { current } = container;

    if (!current) {
      return;
    }

    // this make callback run in outside window
    events.forEach((eventArgs = []) => {
      const [name, callbackName, capture = false] = eventArgs;

      const callback = backend[callbackName] && backend[callbackName].bind(backend);

      current.addEventListener(name, (...args) => {
        callback && callback(...args);
      }, capture);
    });
  }, [container.current]);

  return (
    <Frame className={cls} ref={ref} {...others}>
      <div className="dnd-frame-container" ref={container} {...containerProps}>
        { children }
      </div>
    </Frame>
  );
});

Beschreiben Sie Alternativen, die Sie in Betracht gezogen haben
Möglicherweise können Sie einige Optionen mit HTML5Backend exportieren.

design decisions enhancement pinned

Hilfreichster Kommentar

Ich habe eine einfachere Lösung gefunden, um diesen Code zu vereinfachen, bin mir aber nicht sicher, ob dies eine bessere Lösung ist. Ich hoffe, Ihnen zu helfen, dieses Problem zu beheben.

import React, { useContext, useEffect } from 'react';
import DndProvider, { DndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Frame, { FrameContext } from 'react-frame-component';

const DndFrame = ({ children }) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);

  useEffect(() => {
    dragDropManager.getBackend().addEventListeners(window);
  });

  return children;
};

const Example = () => (
  <DndProvider backend={HTML5Backend}>
    <Frame>
       <DndFrame>
          <div>...</div>
       </DndFrame>
    </Frame>
  </DndProvider>
);

Alle 6 Kommentare

Ich habe eine einfachere Lösung gefunden, um diesen Code zu vereinfachen, bin mir aber nicht sicher, ob dies eine bessere Lösung ist. Ich hoffe, Ihnen zu helfen, dieses Problem zu beheben.

import React, { useContext, useEffect } from 'react';
import DndProvider, { DndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Frame, { FrameContext } from 'react-frame-component';

const DndFrame = ({ children }) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);

  useEffect(() => {
    dragDropManager.getBackend().addEventListeners(window);
  });

  return children;
};

const Example = () => (
  <DndProvider backend={HTML5Backend}>
    <Frame>
       <DndFrame>
          <div>...</div>
       </DndFrame>
    </Frame>
  </DndProvider>
);

@HsuTing Es ist einfacher und besser. Aber immer noch an die HTML5Backend-Schnittstelle gebunden. Wenn HTML5Backend addEventListeners => addListeners ändert, würde unser Web zusammenbrechen

Echt coole Idee, ich spiele damit herum, wenn ich von der Wanderung zurück bin

Am Di, 6. August 2019, 23:43 Uhr schrieb 晓爽[email protected] :

@HsuTing https://github.com/HsuTing Es ist einfacher und besser. Aber dennoch
an HTML5Backend-Schnittstelle gebunden. Wenn HTML5Backend ändert addEventListeners
=> addListeners, unser Web wäre kaputt


Sie erhalten dies, weil Sie zugewiesen wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/react-dnd/react-dnd/issues/1496?email_source=notifications&email_token=AAA3XCDZJS3V5E7YISDRUC3QDJVJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW67GO
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAA3XCGHNHO3M3CSL5VRUQTQDJVJLANCNFSM4IIMWOQQ
.

Ich habe eine einfachere Lösung gefunden, um diesen Code zu vereinfachen, bin mir aber nicht sicher, ob dies eine bessere Lösung ist. Ich hoffe, Ihnen zu helfen, dieses Problem zu beheben.

import React, { useContext, useEffect } from 'react';
import DndProvider, { DndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Frame, { FrameContext } from 'react-frame-component';

const DndFrame = ({ children }) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);

  useEffect(() => {
    dragDropManager.getBackend().addEventListeners(window);
  });

  return children;
};

const Example = () => (
  <DndProvider backend={HTML5Backend}>
    <Frame>
       <DndFrame>
          <div>...</div>
       </DndFrame>
    </Frame>
  </DndProvider>
);

Das ist ein toller Ansatz und funktioniert für mich.

Ich habe eine einfachere Lösung gefunden, um diesen Code zu vereinfachen, bin mir aber nicht sicher, ob dies eine bessere Lösung ist. Ich hoffe, Ihnen zu helfen, dieses Problem zu beheben.

import React, { useContext, useEffect } from 'react';
import DndProvider, { DndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Frame, { FrameContext } from 'react-frame-component';

const DndFrame = ({ children }) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);

  useEffect(() => {
    dragDropManager.getBackend().addEventListeners(window);
  });

  return children;
};

const Example = () => (
  <DndProvider backend={HTML5Backend}>
    <Frame>
       <DndFrame>
          <div>...</div>
       </DndFrame>
    </Frame>
  </DndProvider>
);

Beim Versuch mit Typoskript erhalte ich einen Fehler Property 'addEventListeners' does not exist on type 'Backend'

Gibt es eine Möglichkeit, dies in TS zu beheben?

addEventListeners wird auf der Back-End-Schnittstelle nicht verfügbar gemacht; und ich möchte es nicht veröffentlichen, weil es DOM/Browser-spezifisch ist. Ich denke, was wir wahrscheinlich tun sollten, ist so etwas wie:

// detect if SSR mode
const DEFAULT_GLOBAL_CONTEXT = typeof window !== 'undefined' ? window : global

const DndFrame = ({ children, globalContext = DEFAULT_GLOBAL_CONTEXT}) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);
  const backend = useMemo(() => dragDropManager.getBackend(), [dragDropManager])

  useEffect(() => {
     // This will required adding an initialize() method to the Backend interface.
    // Backend constructors will have to thunk over to it. It could replace constructors, but that would be semver major.
    backend.initialize(dragDropManager, globalContext)
    backend.setup()
  }, [globalContext]);

  return children;
};

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen