React-dnd: طريقة للسحب للخارج إلى iframe

تم إنشاؤها على ١ أغسطس ٢٠١٩  ·  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 ، فسيتم تعطل الويب الخاص بنا

فكرة رائعة حقًا ، سوف ألعب بها عندما أعود من التنزه

في الثلاثاء ، 6 أغسطس ، 2019 ، 11:43 مساءً كتب [email protected] :

HsuTing https://github.com/HsuTing أسهل وأفضل. لكن مازال
مرتبط بواجهة HTML5Backend. إذا كانت تغييرات HTML5Backend تضيفEventListeners
=> addListeners ، سيتم تعطل الويب الخاص بنا

-
أنت تتلقى هذا لأنه تم تعيينك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/react-dnd/react-dnd/issues/1496؟email_source=notifications&email_token=AAA3XCDZJS3V5E7YISDRUC3QDJVJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DFVREXG43TUL52HS4DFVREXG43
أو كتم الخيط
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>
);

عند المحاولة باستخدام الكتابة المطبوعة ، يظهر لي خطأ 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 التقييمات