React-dnd: Un moyen de faire glisser l'extérieur vers l'iframe

Créé le 1 août 2019  ·  6Commentaires  ·  Source: react-dnd/react-dnd

Votre demande de fonctionnalité est liée à un problème ?
React limites que glisser-déposer dans un seul document HTML. D'une manière ou d'une autre, nous devons faire glisser quelque chose à l'extérieur pour l'iframe à l'intérieur.

Décrivez la solution que vous souhaitez
Je trouve que dnd HTML5backend déclenche simplement des rappels de glisser dans la fenêtre. Donc, si nous pouvons faire en sorte que les composants à l'intérieur de l'iframe déclenchent ces rappels React.createPortal Et

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

Décrivez les alternatives que vous avez envisagées
Vous pouvez exporter certaines options avec HTML5Backend.

design decisions enhancement pinned

Commentaire le plus utile

J'ai trouvé une solution plus simple pour simplifier ce code, mais je ne sais pas si celle-ci est une meilleure solution. J'espère vous aider à résoudre ce problème.

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>
);

Tous les 6 commentaires

J'ai trouvé une solution plus simple pour simplifier ce code, mais je ne sais pas si celle-ci est une meilleure solution. J'espère vous aider à résoudre ce problème.

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 C'est plus facile et meilleur. Mais toujours lié à l'interface HTML5Backend. Si HTML5Backend change addEventListeners => addListeners, notre site Web serait en panne

Idée vraiment cool, je vais jouer avec quand je reviens de la randonnée

Le mar 6 août 2019, 23:43 晓爽[email protected] a écrit :

@HsuTing https://github.com/HsuTing C'est plus facile et meilleur. Mais reste
lié à l'interface HTML5Backend. Si HTML5Backend change addEventListeners
=> addListeners, notre web serait en panne

-
Vous recevez ceci parce que vous avez été affecté.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/react-dnd/react-dnd/issues/1496?email_source=notifications&email_token=AAA3XCDZJS3V5E7YISDRUC3QDJVJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DFVREXL3N3QDJVJJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DFVREXL3N3VMXWWW2H630
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAA3XCGHNHO3M3CSL5VRUQTQDJVJLANCNFSM4IIMWOQQ
.

J'ai trouvé une solution plus simple pour simplifier ce code, mais je ne sais pas si celle-ci est une meilleure solution. J'espère vous aider à résoudre ce problème.

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>
);

C'est une excellente approche et ça marche pour moi.

J'ai trouvé une solution plus simple pour simplifier ce code, mais je ne sais pas si celle-ci est une meilleure solution. J'espère vous aider à résoudre ce problème.

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>
);

Lorsque j'essaie avec dactylographe, j'obtiens une erreur Property 'addEventListeners' does not exist on type 'Backend'

y a-t-il un moyen de résoudre ce problème dans TS ?

addEventListeners n'est pas exposé sur l'interface Backend ; et je ne veux pas l'exposer car il est spécifique au DOM/au navigateur. Je pense que ce que nous devrions probablement faire est quelque chose comme :

// 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;
};

Cette page vous a été utile?
0 / 5 - 0 notes