Sua solicitação de recurso está relacionada a um problema?
O React limita o processo de arrastar e soltar em um único documento HTML. De alguma forma, precisamos arrastar algo para fora para o iframe dentro.
Descreva a solução que você gostaria
Acho que dnd HTML5backend apenas aciona callbacks de arrastar na janela. Portanto, se pudermos fazer os componentes dentro do iframe acionar esses callbacks. E React.createPortal
fazer os componentes dentro do iframe ter o mesmo DndProvider com fora. Funciona, felizmente. Mas eu me preocupo com alguns problemas que não percebi. E o código não é tão conveniente com 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>
);
});
Descreva as alternativas que você considerou
Você pode exportar algumas opções com HTML5Backend.
Eu encontrei uma solução mais fácil para simplificar este código, mas não tenho certeza se esta é a melhor solução. Espero ajudá-lo a corrigir esse 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 É mais fácil e melhor. Mas ainda vinculado à interface HTML5Backend. Se HTML5Backend alterar addEventListeners => addListeners, nossa web será quebrada
Uma ideia muito legal, vou brincar com ela quando voltar da caminhada
Na terça-feira, 6 de agosto de 2019, 23h43 晓 爽[email protected] escreveu:
@HsuTing https://github.com/HsuTing É mais fácil e melhor. Mas ainda
vinculado à interface HTML5Backend. Se HTML5Backend mudar addEventListeners
=> addListeners, nossa web seria quebrada-
Você está recebendo isto porque foi designado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/react-dnd/react-dnd/issues/1496?email_source=notifications&email_token=AAA3XCDZJS3V5E7YISDRUC3QDJVJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3XL66Y#issuecomment-518963067 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AAA3XCGHNHO3M3CSL5VRUQTQDJVJLANCNFSM4IIMWOQQ
.
Eu encontrei uma solução mais fácil para simplificar este código, mas não tenho certeza se esta é a melhor solução. Espero ajudá-lo a corrigir esse 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> );
É uma ótima abordagem e funciona para mim.
Eu encontrei uma solução mais fácil para simplificar este código, mas não tenho certeza se esta é a melhor solução. Espero ajudá-lo a corrigir esse 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> );
Ao tentar com o texto digitado, obtenho um erro Property 'addEventListeners' does not exist on type 'Backend'
existe alguma maneira de consertar isso no TS?
addEventListeners não é exposto na interface de back-end; e não quero expô-lo porque é específico do DOM / navegador. Acho que provavelmente deveríamos fazer 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;
};
Comentários muito úteis
Eu encontrei uma solução mais fácil para simplificar este código, mas não tenho certeza se esta é a melhor solução. Espero ajudá-lo a corrigir esse problema.