React-dnd: 外にドラッグしてiframeに移動する方法

作成日 2019年08月01日  ·  6コメント  ·  ソース: react-dnd/react-dnd

機能リクエストは問題に関連していますか?
Reactは、単一のHTMLドキュメント内でのドラッグアンドドロップを制限します。 どういうわけか、外側の何かを内側のiframeにドラッグする必要があります。

希望するソリューションを説明してください
dnd HTML5backendは、ウィンドウでドラッグコールバックをトリガーするだけであることがわかりました。 したがって、iframe内のコンポーネントにこれらのコールバックをトリガーさせることができれば、 React.createPortal iframe内のコンポーネントに外部と同じDndProviderを持たせることができれば、幸いにも機能します。 しかし、私は気づかなかった問題があるかもしれないと心配しています。そして、コードはHTML5Backendではそれほど便利ではありません。

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

検討した代替案を説明してください
HTML5Backendを使用していくつかのオプションをエクスポートできますか。

design decisions enhancement pinned

最も参考になるコメント

このコードを単純化するためのより簡単な解決策を見つけましたが、これがより良い解決策であるかどうかはわかりません。 この問題の解決にご協力いただければ幸いです。

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

全てのコメント6件

このコードを単純化するためのより簡単な解決策を見つけましたが、これがより良い解決策であるかどうかはわかりません。 この問題の解決にご協力いただければ幸いです。

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それはより簡単でより良いです。 しかし、それでもHTML5Backendインターフェースにバインドされています。 HTML5BackendがaddEventListeners => addListenersを変更すると、Webが機能しなくなります

本当にかっこいいアイデアです。ハイキングから戻ったら、遊んでみます。

2019年8月6日火曜日、午後11時43分晓解説[email protected]は次のように書いています。

@HsuTinghttps ://github.com/HsuTingそれはより簡単でより良いです。 それでも
HTML5Backendインターフェイスにバインドされています。 HTML5BackendがaddEventListenersを変更した場合
=> addListeners、私たちのウェブは壊れます


あなたが割り当てられたので、あなたはこれを受け取っています。
このメールに直接返信し、GitHubで表示してください
https://github.com/react-dnd/react-dnd/issues/1496?email_source=notifications&email_token=AAA3XCDZJS3V5E7YISDRUC3QDJVJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNM
またはスレッドをミュートします
https://github.com/notifications/unsubscribe-auth/AAA3XCGHNHO3M3CSL5VRUQTQDJVJLANCNFSM4IIMWOQQ

このコードを単純化するためのより簡単な解決策を見つけましたが、これがより良い解決策であるかどうかはわかりません。 この問題の解決にご協力いただければ幸いです。

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

それは素晴らしいアプローチであり、私にとってはうまくいきます。

このコードを単純化するためのより簡単な解決策を見つけましたが、これがより良い解決策であるかどうかはわかりません。 この問題の解決にご協力いただければ幸いです。

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

typescriptを試してみると、エラーProperty 'addEventListeners' does not exist on type 'Backend'発生します

TSでこれを修正する方法はありますか?

addEventListenersはバックエンドインターフェイスでは公開されません。 DOM /ブラウザ固有であるため、公開したくありません。 私たちがおそらくすべきことは次のようなものだと思います。

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

このページは役に立ちましたか?
0 / 5 - 0 評価