React-dnd: Úselo dentro y / o con un iframe.

Creado en 20 jul. 2015  ·  22Comentarios  ·  Fuente: react-dnd/react-dnd

Cuando el contexto, la fuente y el destino están dentro de un iframe, el DnD no puede deshacerse. Lo rastreé hasta el backend HTML5.js que viene con DnD.
Aunque creo que podría tener algo que ver con una repetición en el iframe. Aquí hay un ejemplo en codepen http://codepen.io/mattconde/pen/zGLXML?editors=101

enhancement wontfix

Comentario más útil

Después de mucho intentarlo, logré colocar elementos dentro de un 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>

¿Parece esta la forma correcta de hacerlo?

Todos 22 comentarios

El arrastrar / soltar fuera de la caja a través de marcos tampoco funcionó para mí. Parece que los eventos de arrastrar / soltar solo deben aplicarse al objeto de ventana de cada marco adicional. Actualmente, solo el objeto de ventana en el que está ejecutando su aplicación de reacción los obtiene:

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

Hice un parche en el backend de HTML5 en mi proyecto reciente para que funcione ( setup y teardown aceptando un objeto de ventana win alternativo):

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

También requiere que la instancia de backend esté expuesta de alguna manera (más parches de mono en DragDropContext.js ...) para ejecutar setup y teardown cuando sea necesario (al configurar sus marcos) .

Pero una vez hecho esto, funciona a las mil maravillas: D

Oh, vaya, bonito hallazgo, tiene mucho sentido. Lo probaré más tarde hoy, ¿se puede evitar el cambio en DragDropContext.js? De esa manera, podríamos crear un nuevo backend como mencionan los documentos.

Me complace considerar una API específica y una propuesta de implementación que aborde este tema.
Desafortunadamente, es difícil digerir desde lo esencial qué se cambió exactamente y por qué.

Por ahora, digamos que no admitimos iframes.

@gaearon Estoy tratando de construir un generador de páginas de arrastrar y soltar. Probé todo lo demás y es horrible trabajar con flux. ¿Puede darme algunas pistas sobre dónde ajustar para que funcione desde el marco cruzado?

@nadimtuhin Yo mismo estaba trabajando en un generador de páginas de marcos cruzados cuando planteé el problema, y ​​comenzaré de nuevo para que funcione una solución de ventanas múltiples esta semana. ¿Está administrando el iframe con react?

Para mí, no estoy seguro de si trabajar dentro de iframes sería la mejor solución, seguro que sería bueno. Pero tener el objetivo de hacer que react-dnd funcione en múltiples aplicaciones parece ser la mejor opción.

Ayer le eché un vistazo breve y acabo de registrar algunos de los identificadores en el backend html5. y la fuente de la primera ventana se detecta en el objetivo de la segunda. Pero eso es todo lo que llegué.

@gaearon Algunos consejos / pistas sobre dónde buscar serían geniales, buscando hacer / intentar mis primeras contribuciones reales de código abierto.

@mattconde no No estoy administrando iframe dentro de mi aplicación de reacción. Planeo tener dos aplicaciones diferentes en dos marcos diferentes. La ventana principal contiene la lógica para la manipulación de datos y el marco secundario para la presentación. El niño obtiene sus accesorios de la tienda de flujo de padres.

@mattconde

Es difícil para mí dar consejos además de "intentar poner registros en el backend HTML5 y luego empezar a modificarlo". Tome el ejemplo más simple posible y vea si puede hacerlo funcionar. El backend solo hace una cosa: se suscribe a eventos de ventana y eventos de nodo, y los traduce en acciones. No sé lo suficiente sobre cómo funcionan los iframes. Tal vez necesite cambiar el código para suscribirse no a la ventana, sino a la ventana de nivel superior del nodo específico (o iframe) si esto tiene sentido. Pero estoy fuera de mi alcance aquí, así que puedo estar hablando tonterías.

@mattconde @gaearon

Tuve el mismo problema recientemente. La razón por la que falla es porque HTML5Backend establece detectores de eventos en la ventana, pero si desea usarlo dentro de un iframe, debería configurarlos en, digamos, window.frames [0].

@gaearon ¿Qué opinas sobre una opción para pasar contexto a la función de configuración / desmontaje en HTML5Backend.js?

He tenido el mismo problema al crear un editor mejorado (texto, imágenes, ..) que funciona dentro de un iframe y necesito arrastrar y soltar elementos (texto, img) dentro de él, básicamente arrastrar y soltar los elementos para cambiar el orden.

Abrí un problema https://github.com/gaearon/react-dnd/issues/435 y descubrí que se debía al iframe. Voy a intentar "modificarlo", pero si hay alguna solución, ¡me alegrará saberlo! :)

Estoy tratando de hacer un PR para que funcione con iframes. Actualmente en progreso, aún no funciona, tengo problemas para averiguar cómo invocar setup y teardown , respectivamente en mi componentDidMount y componentWillUnmount métodos.

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

@Vadorequest Parece que ambos estamos apuntando a un producto final similar. No terminé haciendo que funcionara con react-dnd de la ventana principal a la secundaria. El trabajo que resolví fue tener mi aplicación de editor (padre) y tener una aplicación de vista previa (hijo). La aplicación de vista previa no se procesó hasta que pudo conectarse a la tienda de editors redux.

Luego, en mi tienda redux tenía una lista de plantillas que quería que el usuario arrastrara desde el editor a una gran página de contenido. Entonces, mi lista de plantillas se encontraba en la ventana del Editor, pero me gustaría arrastrarlas a la Vista previa.

Gracias a que react-dnd soporta tipos nativos, pude configurar arrastraciones de texto en la ventana del Editor para pasar la información necesaria para cada plantilla a ser renderizada. Mi fragmento 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;
    },

Entonces pude atrapar esa cadena JSON en el otro extremo con react-dnd , funciona muy bien.

Hágame saber cómo le va, me encantaría conocer formas alternativas de solucionarlo.

@mattconde Estoy trabajando en dos ramas separadas, una solución fea y una solución real para esto. La fea solución simplemente cambia esas líneas en el archivo HTML5Backend.js . Los cambios se pueden ver aquí: https://github.com/Gutenberg-Technology/react-dnd-html5-backend/commit/8b3d6a44b2cdbfe8d5bac025fc263715968d8b6c

_ (Básicamente, solo agrega un parámetro target a setup y teardown , que tiene mi iframe como valor predeterminado y vuelve a usar window . La solución es tan feo que en realidad fallaría si no se encuentra un iframe, pero funcionará por ahora.) _

Pero esto probablemente fallará en alguna situación, si hay más de un iframe, por lo que es solo para evitar atascarse. Una mejor solución sería llamar manualmente setup y teardown dentro de mi propio código simplemente pasando un parámetro target para vincular y desvincular oyentes.

Gracias por explicar su solución, definitivamente mejoraré mis relaciones públicas si encuentro una solución mejor en un futuro cercano. :)

Hola chicos, acabo de encontrarme con este problema, no puedo averiguar cómo conectar la ventana con el iframe. Por ejemplo, quiero tener algo de DragSource en la ventana y quiero crear un DropTarget en iframe, incluso si modifico HTML5Backend no puedo hacer que funcione así ...

@mattconde Gracias por compartir esto. Creo que estoy construyendo un producto final similar. Lo peor es que estamos usando Angular 2. Porté react-dnd a Angular parcialmente, pero finalmente, golpeé la pared con iframe. Voy a probar a tu manera.

@gaearon Los PR aquí ☝️ permiten que react-dnd admita iframes. Si tiene alguna inquietud o necesita que cambie algo, hágamelo saber.

@kesne ¿Eres el nuevo mantenedor? ¿Puedes revisar estos RP?

Hola @darthtrevino
¿Tus cambios permiten arrastrar un elemento de la página a un marco?
Puedo arrastrar y soltar dentro y fuera del marco.

Hola @crysislinux , estoy buscando

¿Hay alguna manera de soltar elementos que están fuera del iframe dentro del iframe, por ejemplo:

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

Después de mucho intentarlo, logré colocar elementos dentro de un 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>

¿Parece esta la forma correcta de hacerlo?

@ethanve Acabo de encontrar este hilo por un problema de incautación: construí lo que describiste. https://cormacrelf.github.io/angular-skyhook/

También tengo problemas para usar dnd dentro de un iframe (sin interacción con los padres). Arrastrar funciona bien, pero las zonas de colocación ya no funcionan. ¿Cuál es la solución para hacer que las zonas de colocación funcionen dentro de un iframe (simplemente moviendo el elemento completamente dentro del iframe)?

Quiero señalar que funciona con el backend Touch pero no con el backend HTML5.

¿Fue útil esta página
0 / 5 - 0 calificaciones