React-dnd: Use dentro e / ou com um iframe.

Criado em 20 jul. 2015  ·  22Comentários  ·  Fonte: react-dnd/react-dnd

Quando o contexto, a origem e o destino estão dentro de um iframe, o DnD não muda. Rastreei de volta ao back-end HTML5.js que vem com o DnD.
Embora eu ache que pode ter algo a ver com um rerender no iframe. Aqui está um exemplo no codepen http://codepen.io/mattconde/pen/zGLXML?editors=101

enhancement wontfix

Comentários muito úteis

Depois de muitas tentativas, consegui soltar elementos dentro de um iframe como este:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import FrameComponent from 'react-frame-component';

class DragDropAwareIFrame extends Component {
  static propTypes = {
    innerRef: PropTypes.func,
  };

  static contextTypes = {
    dragDropManager: PropTypes.object.isRequired,
  }

  constructor(props, context) {
    super(props, context);

    this.manager = this.context.dragDropManager;
  }

  componentDidMount() {
    const iframe = ReactDOM.findDOMNode(this.iframe);
    this.manager.getBackend().addEventListeners(iframe.contentWindow);
  }

  componentWillUnmount() {
    const iframe = ReactDOM.findDOMNode(this.iframe);
    this.manager.getBackend().removeEventListeners(iframe.contentWindow);
  }

  handleRef = (el) => {
    this.iframe = el;
    if (this.props.innerRef) this.props.innerRef(el);
  }

  render() {
    const { innerRef, ...props } = this.props;
    return <FrameComponent {...props} ref={this.handleRef} />;
  }
}

<DragDropContextProvider backend={HTML5Backend}>
    <div>
        <Item />
        <DragDropAwareIFrame>
            <div>
                <Dustbin />
            </div>
        </DragDropAwareIFrame>
    </div>
</DragDropContextProvider>

Esta parece ser a maneira certa de fazer isso?

Todos 22 comentários

Arrastar / soltar fora da caixa nos quadros também não funcionou para mim. Parece que os eventos de arrastar / soltar precisam apenas ser aplicados a cada objeto de janela de quadro adicional. Atualmente, apenas o objeto de janela no qual você está executando seu aplicativo react os obtém:

https://github.com/gaearon/react-dnd/blob/master/src/backends/HTML5.js#L130 -L139

Eu fiz um monkey-patch no HTML5-backend em meu projeto recente para fazê-lo funcionar ( setup e teardown aceitando um objeto de janela win alternativo):

https://gist.github.com/rasmusfl0e/39db428399bd196ef706

Também requer que a instância de back-end seja exposta de alguma forma (mais patching em DragDropContext.js ...) para executar setup e teardown quando necessário (na configuração de seus quadros) .

Mas uma vez feito isso - funciona perfeitamente: D

Oh wow nice find, faz muito sentido. Vou tentar mais tarde hoje, a mudança em DragDropContext.js pode ser evitada? Dessa forma, poderíamos apenas criar um novo back-end como a menção dos documentos.

Estou feliz em considerar uma API específica e uma proposta de implementação abordando isso.
Infelizmente, é difícil digerir o que exatamente foi alterado e por quê.

Por enquanto, digamos que não oferecemos suporte a iframes.

@gaearon Estou tentando construir um construtor de arrastar e soltar. Tentei de tudo e eles são horríveis de trabalhar com fluxo. Pode me dar algumas dicas de onde ajustar para que funcione a partir do quadro cruzado?

@nadimtuhin Eu mesmo estava trabalhando em um criador de páginas cross frame quando levantei o problema e vou começar novamente a obter uma solução de janela múltipla funcionando esta semana. Você está gerenciando o iframe com react?

Para mim, não tenho certeza se trabalhar dentro de iframes seria a melhor solução, com certeza seria bom. Mas ter o objetivo de fazer o react-dnd funcionar em vários aplicativos parece ser a melhor opção.

Eu dei uma olhada nisso ontem e acabei de registrar alguns dos identificadores no back-end html5. e a fonte da primeira janela está sendo detectada no alvo da segunda. Mas foi o mais longe que consegui.

@gaearon Algumas dicas / pistas sobre onde olhar seriam ótimas, procurando fazer / tentar minhas primeiras contribuições de código aberto real.

@mattconde não, não estou gerenciando iframe dentro do meu app

@mattconde

É difícil para mim dar qualquer indicação além de "tente colocar logs no back-end do HTML5 e, em seguida, comece a ajustá-lo". Pegue o exemplo mais simples possível e veja se você pode fazer funcionar. O backend só faz uma coisa: assina eventos de janela e eventos de nó e os traduz em ações. Não sei o suficiente sobre como funcionam os iframes. Talvez você precise alterar o código para se inscrever não na janela, mas na janela de nível superior do nó específico (ou iframe), se isso fizer sentido. Mas estou muito longe de minha profundidade aqui, então posso estar falando bobagem.

@mattconde @gaearon

Eu tive o mesmo problema recentemente. O motivo da falha é porque HTML5Backend define ouvintes de evento na janela, mas se você quiser usá-lo dentro do iframe, você deve defini-los em, digamos, window.frames [0].

@gaearon O que você acha sobre uma opção para passar contexto para a função de configuração / desmontagem em HTML5Backend.js?

Tenho encontrado o mesmo problema, ao construir um editor aprimorado (texto, imagens, ..) que funciona dentro de um iframe e preciso arrastar e soltar elementos (texto, img) dentro dele, basicamente arrastar e soltar os elementos para alterar o ordem.

Abri um problema https://github.com/gaearon/react-dnd/issues/435 e descobri que era por causa do iframe. Vou tentar "ajustá-lo", mas se houver alguma solução, ficarei feliz em saber! :)

Estou tentando fazer um PR para que funcione com iframes. Atualmente em andamento, ainda não funciona. Estou tendo problemas para descobrir como invocar setup e teardown , respectivamente em meus componentDidMount e componentWillUnmount métodos.

https://github.com/gaearon/react-dnd-html5-backend/pull/27

@Vadorequest Parece que ambos react-dnd da janela pai para filho. A solução que resolvi foi ter meu aplicativo editor (pai) e um aplicativo de visualização (filho). O aplicativo de visualização não foi renderizado até que pudesse se conectar à loja redux dos editores.

Então, em minha loja redux, eu tinha uma lista de modelos que desejo que o usuário arraste do editor para uma página de conteúdo excelente. Portanto, minha lista de modelos estava na janela do Editor, mas gostaria de arrastá-los para a Visualização.

Graças ao suporte de react-dnd a tipos nativos, eu poderia configurar arrastamentos de texto na janela do Editor para passar as informações necessárias para cada modelo a ser renderizado. Meu snippet de código ...

    componentDidMount() {
        this.refs.template.addEventListener('dragstart', this.handleDragStart, false);
    },
    componentWillUnmount() {
        this.refs.template.removeEventListener('dragstart', this.handleDragStart, false);
    },
    handleDragStart(e) {
        const { template } = this.props;
        e.dataTransfer.setData('text/plain', JSON.stringify({
            type: template.type,
            name: template.name,
        }));
        return e;
    },

Então eu poderia pegar aquela string JSON na outra extremidade com react-dnd , funciona muito bem.

Deixe-me saber como você está, adoraria ouvir sobre maneiras alternativas de contornar isso.

@mattconde Estou trabalhando em dois ramos separados, uma correção feia e uma correção real para isso. A correção feia simplesmente muda essas linhas no arquivo HTML5Backend.js . As alterações podem ser visualizadas aqui: https://github.com/Gutenberg-Technology/react-dnd-html5-backend/commit/8b3d6a44b2cdbfe8d5bac025fc263715968d8b6c

_ (basicamente, adiciona um parâmetro target a setup e teardown , que tem meu iframe como valor padrão e volta a usar window . A correção é tão feio que falharia se nenhum iframe fosse encontrado, mas servirá por enquanto.) _

Mas isso provavelmente falhará em alguma situação, se houver mais de um iframe, então é apenas para evitar travar. Uma solução melhor seria chamar manualmente setup e teardown dentro do meu próprio código apenas passando um parâmetro target para ligar e desligar os ouvintes.

Obrigado por explicar sua solução, com certeza vou melhorar meu PR se encontrar uma solução alternativa melhor em um futuro próximo. :)

Ei pessoal, acabei de encontrar esse problema sozinho, não consigo descobrir como conectar a janela com iframe. Por exemplo, eu quero ter um DragSource na janela e quero criar algum DropTarget no iframe, mesmo se eu ajustar o HTML5Backend, não consigo fazer funcionar assim ...

@mattconde Obrigado por compartilhar isso. Estou construindo um produto final semelhante, eu acho. A pior coisa é que estamos usando Angular 2. Portei o react-dnd para o Angular parcialmente, mas, finalmente, bati na parede com o iframe. Vou tentar do seu jeito.

@gaearon Os PRs aqui ☝️ permitem o react-dnd para suportar iframes. Se você tiver alguma dúvida ou precisar que eu mude alguma coisa, me avise.

@kesne Você é o novo mantenedor? Você pode revisar esses PRs?

Oi @darthtrevino
Suas alterações permitem arrastar um elemento da página para um quadro?
Posso arrastar e soltar dentro e fora do Quadro.

Olá @crysislinux , estou procurando portar esta biblioteca para Angular 2 e adoraria ver o que vocês criaram. Você gostaria de compartilhar seu código? Obrigado!

existe uma maneira de descartar itens que estão fora do iframe dentro do iframe, por exemplo:

<DragDropContextProvider backend={HTML5Backend}>
    <div>
        <Item />
        <Frame>
            <div>
                <Dustbin />
            </div>
        </Frame>
    </div>
</DragDropContextProvider>

Depois de muitas tentativas, consegui soltar elementos dentro de um iframe como este:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import FrameComponent from 'react-frame-component';

class DragDropAwareIFrame extends Component {
  static propTypes = {
    innerRef: PropTypes.func,
  };

  static contextTypes = {
    dragDropManager: PropTypes.object.isRequired,
  }

  constructor(props, context) {
    super(props, context);

    this.manager = this.context.dragDropManager;
  }

  componentDidMount() {
    const iframe = ReactDOM.findDOMNode(this.iframe);
    this.manager.getBackend().addEventListeners(iframe.contentWindow);
  }

  componentWillUnmount() {
    const iframe = ReactDOM.findDOMNode(this.iframe);
    this.manager.getBackend().removeEventListeners(iframe.contentWindow);
  }

  handleRef = (el) => {
    this.iframe = el;
    if (this.props.innerRef) this.props.innerRef(el);
  }

  render() {
    const { innerRef, ...props } = this.props;
    return <FrameComponent {...props} ref={this.handleRef} />;
  }
}

<DragDropContextProvider backend={HTML5Backend}>
    <div>
        <Item />
        <DragDropAwareIFrame>
            <div>
                <Dustbin />
            </div>
        </DragDropAwareIFrame>
    </div>
</DragDropContextProvider>

Esta parece ser a maneira certa de fazer isso?

@ethanve Acabei de encontrar este tópico por causa de um problema de ingênuo - eu construí o que você descreveu. https://cormacrelf.github.io/angular-skyhook/

Também estou tendo problemas ao usar dnd em um iframe (sem interação com os pais). Arrastar funciona bem, mas as zonas para soltar não funcionam mais. Qual é a solução para fazer as zonas para soltar funcionarem dentro de um iframe (apenas movendo o item inteiramente dentro do iframe).

Quero ressaltar que ele funciona com o back-end Touch, mas não com o back-end HTML5.

Esta página foi útil?
0 / 5 - 0 avaliações