React-dnd: Mauvaise capture d'écran lors du glissement normal, mouvement saccadé sur l'aperçu du glissement personnalisé

Créé le 8 mai 2016  ·  22Commentaires  ·  Source: react-dnd/react-dnd

Comme beaucoup, j'ai une liste de cartes triables. Dans mon cas, chaque carte est un bloc de contenu d'un article de blog et certains d'entre eux sont des extraits de code rendus avec react-codemirror . L'aperçu de glissement pour les extraits incluait un grand fond blanc qui était égal à la largeur et à la hauteur du texte dans l'éditeur de code de codemirror. Ce n'était pas souhaitable, j'ai donc essayé de le réparer avec CSS mais sans succès, et alors que je lis plus de documentation, je pense que ce n'est pas possible car dnd effectue une capture d'écran du nœud dom avant que de nouvelles classes ou de nouveaux styles ne puissent y être appliqués (veuillez me corriger si c'est faux bien sur)

Parce que je ne pouvais pas faire fonctionner CSS, j'ai essayé d'utiliser un calque de glissement personnalisé pour afficher quelque chose de différent pour l'aperçu. Cela fonctionne très bien, sauf que le glissement devient vraiment saccadé là où il était en fait assez fluide auparavant.

Voici une vidéo illustrant le problème que je viens de décrire :

https://drive.google.com/file/d/0Bzbw-6Q_sVTySUNiNmJGcFVIQ00/view?usp=sharing

Et je suppose que vous voudrez aussi voir du code. Voici mon calque de glissement personnalisé

import React, { Component, PropTypes } from 'react'
import { DragLayer } from 'react-dnd'

function collect(monitor) {
  return {
    item: monitor.getItem(),
    currentOffset: monitor.getSourceClientOffset(),
    isDragging: monitor.isDragging()
  }
}

const layerStyles = {
  position: 'fixed',
  pointerEvents: 'none',
  zIndex: 100,
  left: 0,
  top: 0,
  width: '20%',
  height: '100%'
}

function getItemStyles(props) {
  var currentOffset = props.currentOffset
  if (!currentOffset) {
    return {
      display: 'none'
    }
  }

  var x = currentOffset.x
  var y = currentOffset.y
  var transform = 'translate(' + x + 'px, ' + y + 'px)'
  return {
    transform: transform,
    WebkitTransform: transform
  }
}

class CardDragLayer extends Component {
  static propTypes = {
    item: PropTypes.object
  }

  render() {
    const { item, isDragging } = this.props

    if (!isDragging)
      return false

    return (
      <div style={layerStyles}>
        <div className='drag-preview' style={getItemStyles(this.props)}>
          <i className='fa fa-hand-scissors-o fa-6'></i>
        </div>
      </div>
    )
  }
}

export default DragLayer(collect)(CardDragLayer)

Voici les options de configuration pour la source de glisser et la cible de dépôt

export const cardSource = {
  beginDrag(props) {
    return {
      index: props.index
    }
  }
}

export const cardTarget = {
  hover(props, monitor, component) {
    const dragIndex = monitor.getItem().index
    const hoverIndex = props.index

    if (dragIndex === hoverIndex)
      return

    props.swap(dragIndex, hoverIndex)
    monitor.getItem().index = hoverIndex;
  }
}

export function collectSource(connect, monitor) {
  return {
    connectDragSource: connect.dragSource(),
    connectDragPreview: connect.dragPreview(),
    isDragging: monitor.isDragging()
  }
}

export function collectTarget(connect) {
  return {
    connectDropTarget: connect.dropTarget()
  }
}

Et voici le composant Card qui est déplacé

import React, { PropTypes, Component } from 'react'
import { Snippet, Markdown } from './Show'
import { DragSource, DropTarget } from 'react-dnd'
import { getEmptyImage } from 'react-dnd-html5-backend'
import { cardSource, cardTarget, collectSource, collectTarget } from './dragDropConfig'
import classnames from 'classnames'

class SnippetCard extends Component {
  options() {
    return {
      readOnly: true,
      scrollbarStyle: 'null',
      viewportMargin: Infinity
    }
  }

  render() {
    const { language, text } = this.props
    return(
      <Snippet
        options={this.options()}
        language={language.value}
        text={text.value} />
    )
  }
}

class MarkdownCard extends Component {
  render() {
    const { text } = this.props
    return (
      <div className='markdown-card'>
        <div className='card-content'>
          <Markdown text={text.value} />
        </div>
      </div>
    )
  }
}

const components = {
  snippet: SnippetCard,
  markdown: MarkdownCard
}

class Card extends Component {
  static propTypes = {
    connectDragSource: PropTypes.func.isRequired,
    connectDropTarget: PropTypes.func.isRequired,
    index: PropTypes.number.isRequired,
    block: PropTypes.object.isRequired,
    swap: PropTypes.func.isRequired
  }

  componentDidMount() {
    const { connectDragPreview } = this.props
    connectDragPreview(getEmptyImage(), {
      captureDraggingState: true
    })
  }

  render() {
    const { isDragging, block, connectDragSource, connectDropTarget } = this.props
    const Component = components[block.format.value]
    const classes = classnames('card', {
      dragging: isDragging
    })

    return connectDragSource(connectDropTarget((
      <div className={classes}>
        <div className='card-header'>
          <div>
            <label>
              {block.format.value}
            </label>
          </div>
          <Component {...block} />
        </div>
      </div>
    )))
  }
}

const Source = DragSource('card', cardSource, collectSource)(Card)
export default DropTarget('card', cardTarget, collectTarget)(Source)

Faites-moi savoir si vous avez besoin de voir plus de code que cela, je pense que cela devrait être suffisant.

Des suggestions pour a) comment je pourrais utiliser css pour masquer l'arrière-plan blanc ou b) rendre l'aperçu du glissement personnalisé plus fluide seraient très appréciées !

Notez que ce travail fait partie d'un cours de screencast sur la création d'applications avec react/redux et que je prévois de faire probablement 2-3 courtes vidéos sur react-dnd pour montrer comment les cartes de blocage de contenu triables sont implémentées. En espérant les publier au plus vite !

needs info wontfix

Commentaire le plus utile

Oui, nous avons commencé par supprimer chaque composant pour trouver celui qui causait le problème, et une fois que nous l'avons trouvé, nous avons exploré la partie qui causait le ralentissement, puis l'élément le plus à l'extérieur qui peut accepter un style param nous avons écrit : style={{transform: translate3d(0, 0, 0)}}

Tous les 22 commentaires

J'ai également remarqué des saccades avec le dragLayer personnalisé (en exécutant simplement l'exemple du site Web): http://gaearon.github.io/react-dnd/examples-drag-around-custom-drag-layer.html

Tout va bien dans Chrome mais l'animation est saccadée dans Firefox. (sur linux mint, firefox 46.0.1)

Superbe bibliothèque d'ailleurs !

@sslotsky Avez-vous déjà

Sinon, je peux m'y plonger et voir s'il y a quelque chose d'intelligent dans CSS que nous pouvons faire, ou bien tout ce que nous pouvons faire pour réduire le clapot. D'autres personnes ont signalé que les performances de la couche de glissement personnalisée laissent beaucoup à désirer.

Non, je n'ai toujours pas compris. Une solution serait géniale lorsque je me mettrai à enregistrer la prochaine vidéo !

Nous voyons également cela aussi, en vous abonnant à ce problème pour toute mise à jour

@kesne Je commente juste pour garder cela en vie. Si vous avez des mises à jour à partager, je suis sûr que nous aimerions en entendre parler :)

Oui, j'aimerais aussi une solution à ce problème. Je cherche à implémenter plus qu'une simple capture d'écran de l'objet déplaçable, mais essentiellement un composant de réaction super simple.

Je vais me lancer là-dessus aussi. Nous constatons également le même problème.

Je suis également confronté à cela. Un simple glisser-déposer fonctionne bien. Mais j'ai une implémentation qui est trop complexe, et c'est ce qui se passe.

Avoir le même problème. Quelqu'un a-t-il trouvé une solution ou une solution de contournement ?

@alexey-belous Nous avons supprimé cette bibliothèque et sommes allés avec https://github.com/bevacqua/react-dragula

Même problème ici, je serais heureux de recevoir d'autres commentaires.

J'ai enquêté sur ce problème et j'ai découvert que la capture d'écran du déplacement du nœud dom n'est transparente que sous Windows, indépendamment du navigateur.

J'ai pu améliorer considérablement la qualité en supprimant simplement un console.log() de ma méthode getItemStyles(props). Cela n'aide pas le PO, mais peut-être que quelqu'un d'autre trébuche ici.

J'ai donc cloné cela et exécuté le serveur de développement et l'exemple d'aperçu de glissement personnalisé est également saccadé. Cependant, lorsque je crée le site (en exécutant npm run build-site ), le site est converti en balisage normal (sans références de composant React) et maintenant l'exemple de prévisualisation par glisser s'exécute correctement.

Mon hypothèse est donc que ReactDOM.renderToString( ) améliore les performances de glisser-déposer pour un aperçu de glisser personnalisé.

C'est toujours un problème majeur... :(

592 Semble avoir eu de la chance, mais je n'ai pas encore été capable de bifurquer et d'éditer. Peut-être que quelqu'un d'autre pourra y accéder avant moi.

@gaearon on t'aime mec ! Ne nous laissez pas pendre ! Dirigez-nous dans la bonne direction et je suis sûr que nous allons y remédier :)

J'avais un problème avec l'animation saccadée sur un calque de glissement personnalisé et j'ai découvert que c'était à cause d'un arbre DOM extrêmement complexe.

Je travaille sur une application qui a un composant de table qui peut afficher jusqu'à des milliers de lignes et de colonnes de données tabulaires, ce qui crée quelque chose comme 4 éléments DOM par cellule environ. Lorsque la table était vide, la couche de glissement fonctionnait correctement, mais à mesure que la quantité de données affichées dans la table augmentait, les performances de la couche de glissement personnalisée ont ralenti. (Dans ce cas, la table n'intervient pas du tout dans le fonctionnement des sources de glisser ou des cibles de dépôt).

Dans ce cas, les performances de Firefox n'ont pas changé, tandis que les performances de Chrome se sont considérablement dégradées à mesure que la complexité de l'arborescence DOM augmentait.

J'ai pu résoudre le problème en poussant la table dans sa propre couche de composition dans Chrome, en la stylisant avec une propriété de transformation 3D vide : transform: translate3d(0, 0, 0)

Après cela, les performances étaient comparables à celles de la page de démonstration. Je ne sais pas quelles sont les implications pour cette bibliothèque, mais en poussant des parties complexes de l'arborescence DOM de votre application dans des couches de composition distinctes, vous pourrez peut-être résoudre vos problèmes de performances.

@mgerring Avez-vous plus d'informations sur la façon dont vous avez fait cela? J'aimerais l'essayer sur mon application

Oui, nous avons commencé par supprimer chaque composant pour trouver celui qui causait le problème, et une fois que nous l'avons trouvé, nous avons exploré la partie qui causait le ralentissement, puis l'élément le plus à l'extérieur qui peut accepter un style param nous avons écrit : style={{transform: translate3d(0, 0, 0)}}

Je voulais laisser ce commentaire sur #592 mais je pense qu'il s'applique ici aussi

La solution

@alexey-belous Nous avons supprimé cette bibliothèque et sommes allés avec https://github.com/bevacqua/react-dragula
+1

Ce problème a été automatiquement marqué comme obsolète car il n'a pas eu d'activité récente. Il sera fermé si aucune autre activité ne se produit. Merci pour vos contributions.

Cette page vous a été utile?
0 / 5 - 0 notes