¿Su solicitud de función está relacionada con un problema?
Reaccionar límites que arrastran y sueltan dentro de un solo documento HTML. De alguna manera necesitamos arrastrar algo afuera al iframe adentro.
Describe la solución que te gustaría
Encuentro que dnd HTML5backend solo activa las devoluciones de llamada de arrastre en la ventana. Entonces, si podemos hacer que los componentes dentro del iframe activen esas devoluciones React.createPortal
llamada, y
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>
);
});
Describe las alternativas que has considerado
Puede exportar algunas opciones con HTML5Backend.
Encontré una solución más fácil para simplificar este código, pero no estoy seguro si esta es una mejor solución. Espero ayudarlo a solucionar este problema.
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 más fácil y mejor. Pero aún vinculado a la interfaz HTML5Backend. Si HTML5Backend cambia addEventListeners => addListeners, nuestra web se romperá
Una idea realmente genial, jugaré con ella cuando regrese de la caminata.
El martes 6 de agosto de 2019 a las 11:43 p.m. 晓 爽[email protected] escribió:
@HsuTing https://github.com/HsuTing Es más fácil y mejor. Pero aún
enlazado a la interfaz HTML5Backend. Si HTML5Backend cambia addEventListeners
=> addListeners, nuestra web se rompería-
Está recibiendo esto porque fue asignado.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/react-dnd/react-dnd/issues/1496?email_source=notifications&email_token=AAA3XCDZJS3V5E7YISDRUC3QDJVJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DVDMVREXWWK3TUL52HS4DFZVLOXWG43 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAA3XCGHNHO3M3CSL5VRUQTQDJVJLANCNFSM4IIMWOQQ
.
Encontré una solución más fácil para simplificar este código, pero no estoy seguro si esta es una mejor solución. Espero ayudarlo a solucionar este problema.
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> );
Es un gran enfoque y me funciona.
Encontré una solución más fácil para simplificar este código, pero no estoy seguro si esta es una mejor solución. Espero ayudarlo a solucionar este problema.
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> );
Cuando intento con mecanografiado, obtengo un error Property 'addEventListeners' does not exist on type 'Backend'
¿Hay alguna forma de solucionar esto en TS?
addEventListeners no está expuesto en la interfaz Backend; y no quiero exponerlo porque es específico de DOM / navegador. Creo que lo que probablemente deberíamos hacer es algo como:
// 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;
};
Comentario más útil
Encontré una solución más fácil para simplificar este código, pero no estoy seguro si esta es una mejor solución. Espero ayudarlo a solucionar este problema.