Question Obtenir les positions de décalage des positions supérieures dans React


J'essaie d'implémenter une vue Liste dans React. Ce que j'essaie de faire, c'est de stocker les informations des en-têtes de liste et d'enregistrer les composants et d'enregistrer l'événement de défilement. chaque fois que l'utilisateur fait défiler la fenêtre, je voudrais sortir le div stocké et recalculer le offsetTop Les données.

Le problème est que maintenant, j'ai trouvé la console juste imprimer la valeur initiale (la valeur est fixe et jamais modifiée) offsetTop les données ne changent jamais onscroll fonction.

Quelqu'un suggère comment obtenir les dernières informations offsetTop du _instances objet?

import React, { Component } from 'react';
import ListHeader from './lib/ListHeader';
import ListItems from './lib/ListItems';

const styles = {
  'height': '400px',
  'overflowY': 'auto',
  'outline': '1px dashed red',
  'width': '40%'
};

class HeaderPosInfo {
  constructor(headerObj, originalPosition, originalHeight) {
    this.headerObj = headerObj;
    this.originalPosition = originalPosition;
    this.originalHeight = originalHeight; 
  }
}

export default class ReactListView extends Component {
  static defaultProps = {
    events: ['scroll', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll', 'resize', 'touchmove', 'touchend'],
    _instances:[],
    _positionMap: new Set(),
    _topPos:'',
    _topWrapper:''
  }

  static propTypes = {
    data: React.PropTypes.array.isRequired,
    headerAttName: React.PropTypes.string.isRequired,
    itemsAttName: React.PropTypes.string.isRequired,
    events: React.PropTypes.array,
    _instances: React.PropTypes.array,
    _positionMap: React.PropTypes.object,
    _topPos: React.PropTypes.string,
    _topWrapper: React.PropTypes.object
  };

  state = {
    events: this.props.events,
    _instances: this.props._instances,
    _positionMap: this.props._positionMap,
    _topPos: this.props._topPos
  }

  componentDidMount() {
    this.initStickyHeaders();
  }

  componentWillUnmount() {

  }

  componentDidUpdate() {

  }

  refsToArray(ctx, prefix){
    let results = [];
    for (let i=0;;i++){
      let ref = ctx.refs[prefix + '-' + String(i)];
      if (ref) results.push(ref);
      else return results;
    }
  }

  initHeaderPositions() {
    // Retrieve all instance of headers and store position info
    this.props._instances.forEach((k)=>{
      this.props._positionMap.add(new HeaderPosInfo(
          k, 
          k.refs.header.getDOMNode().offsetTop,
          k.refs.header.getDOMNode().offsetHeight
        ));
    });
    let it = this.props._positionMap.values();
    let first = it.next();
    this.props._topPos = first.value.originalPosition;
    this.props._topWrapper = first.value.headerObj;
  }

  initStickyHeaders () {
    this.props._instances = this.refsToArray(this, 'ListHeader');
    this.initHeaderPositions();

    // Register events listeners with the listview div
    this.props.events.forEach(type => {
      if (window.addEventListener) {
        React.findDOMNode(this.refs.listview).addEventListener(type, this.onScroll.bind(this), false);
      } else {
        React.findDOMNode(this.refs.listview).attachEvent('on' + type, this.onScroll.bind(this), false);
      }
    });
  }

  onScroll() {

    // update current header positions and apply fixed positions to the top one
    console.log(1);
    let offsetTop  = React.findDOMNode(this.props._instances[0].refs.header).offsetTop;

  }

  render() {
    const { data, headerAttName, itemsAttName } = this.props;
    let _refi = 0;
    let makeRef = () => {
      return 'ListHeader-' + (_refi++);
    };

    return (
      <div ref="listview" style={styles}>
      {
        Object.keys(data).map(k => {
        const header = data[k][headerAttName];
        const items  = data[k][itemsAttName];
          return (
            <ul key={k}>     
              <ListHeader ref={makeRef()} header={header} />
              <ListItems  items={items} />
            </ul>
          );
        })
      }
      </div>
    );
  }
}

Le code source complet est sur Github, vous pouvez le cloner et le compiler à partir d'ici:

Github


25
2017-09-19 11:47


origine


Réponses:


Vous pouvez être encouragé à utiliser le Element.getBoundingClientRect () méthode pour obtenir le décalage supérieur de votre élément. Cette méthode fournit les valeurs de décalage complètes (gauche, haut, droite, bas, largeur, hauteur) de votre élément dans la fenêtre.

Vérifier la Le post de John Resig décrivant comment cette méthode est utile.


43
2017-09-23 07:02



La réponse d'Eugene utilise la fonction correcte pour obtenir les données, mais pour la postérité, j'aimerais préciser comment l'utiliser dans React v0.14 + (d'après cette réponse):

  import ReactDOM from 'react-dom';
  //...
  componentDidMount() {
    var rect = ReactDOM.findDOMNode(this)
      .getBoundingClientRect()
  }

Fonctionne parfaitement pour moi et j'utilise les données pour atteindre le haut du nouveau composant qui vient d'être monté.


16
2017-07-24 18:32



  import ReactDOM from 'react-dom';
  //...
  componentDidMount() {
    var n = ReactDOM.findDOMNode(this);
    console.log(n.offsetTop);
  }

Vous pouvez simplement saisir l'offsetTop du nœud.


4
2018-03-18 13:51



Une meilleure solution avec ref pour éviter findDOMNode qui est déconseillé.

...
onScroll() {
    let offsetTop  = this.instance.getBoundingClientRect().top;
}
...
render() {
...
<Component ref={(el) => this.instance = el } />
...

3
2018-02-20 17:00