Случайным образом установить свойство top элемента на основе родительской высоты при рендеринге

#javascript #html #reactjs

#javascript #HTML #reactjs

Вопрос:

Я создал компонент мерцающей звезды CSS, который создает 300 div пикселей и размещает их случайным образом на основе высоты и ширины окна просмотра. Это работает почти идеально, пока не вступит в игру мобильное форматирование, и в этот момент начальный контейнер, который должны заполнить звездочки, имеет высоту больше, чем окно просмотра, поэтому звездочки резко останавливаются, как только вы начинаете прокручивать вниз.

Есть ли способ получить значение высоты компонента, в котором отображаются звезды? Мой код выглядит следующим образом:

 //Stars.js
const Star = styled.div`
    animation: ${flicker} infinite;
    animation-duration: ${props => props.animationDuration   1}s;
    animation-delay: ${props => props.animationDelay}s;
    width: ${props => props.size}px;
    height: ${props => props.size}px;
    position: absolute;
    border-radius: 2px;
    background: white;
`
const StarContainer = styled.div`
    position: absolute;
    top: 0;
    left: 0;
    overflow: hidden;
    width: 100%;
    height: 100%;
`
const vpHeight = window.innerHeight;
const vpWidth = window.innerWidth;
const starCount = () => {
    const count = []
    for(let i = 1; i <= 300; i  ){
        count.push(i)
    }
    return count
}

const Stars = () => {

    const starsRef = useRef(null)

    return (
        <StarContainer ref={starsRef} id='star-container'>
            {starCount().map((star, i) => (
                <Star 
                key={i}
                animationDuration={Math.floor(Math.random() * 2)}
                animationDelay={Math.random() * 6}
                size={Math.random() * 5}
                style={{
                    top: `${Math.floor(Math.random() * vpHeight)}px`,
                    left: `${Math.floor(Math.random() * vpWidth)}px`,
                }} />
            ))}
        </StarContainer>
    );
}

export default Stars;
  

И компонент, над которым отображаются звезды:

 function Skillset() {
    const icons = images.icons
    const skillsetRef = useRef(null)
    return (
        <div ref={skillsetRef} id='skillset' className={styles.skillsetContent}>
            <Stars />
            <Header>I am a Front End Developer who specializes in React.js</Header>
            <Tag>Some of my favorite technologies include:</Tag>
            <div className={styles.iconGrid}>
                <AnimatedCards number={icons.length} data={icons} hoverText={true} />
            </div>
        </div>
    );
}

export default Skillset;
  

Как вы можете видеть, я пытался использовать useRef для доступа к содержащему компоненту и получения skillsetRef.current.offsetHeight , передавая это в качестве реквизита Stars компоненту и устанавливая это в качестве множителя высоты, а не высоты окна просмотра. Однако в нем говорится, что значение равно null, и я полагаю, это из-за порядка, в котором создается ссылка, по сравнению с порядком создания компонента stars. Я в недоумении, что попробовать дальше.

Ответ №1:

skillsetRef.current будет доступно только после первоначального рендеринга. Вы могли бы отложить рендеринг звездочек до тех пор, пока не получите skillsetRef.current значение

 const [refAvailable, setRefAvailable] = useState(false);


useEffect(() => {
  if(!refAvailable) {
    setRefAvailable(true);
  }
}, [refAvailable]);



// Render stars only when you have the ref.current available
refAvailable amp;amp; <Stars height={skillsetRef.current.offsetHeight}/>
  

Другой идеей было бы использовать значения top и left в процентах вместо px.

 style={{
  top: `${Math.floor(Math.random() * 100)}%`,
  left: `${Math.floor(Math.random() * 100)}%`,
}} />
  

Вы также могли бы добавить некоторый буфер к высоте окна просмотра, чтобы обслуживать мобильные браузеры.

 const vpHeight = window.innerHeight   100;
  

Комментарии:

1. К сожалению, ни один из способов не работает. По какой-то причине они оба, похоже, возвращают высоту просмотра. Я не уверен, что контейнер div не был полностью развернут при первоначальном рендеринге или что, поскольку у меня установлено значение height, равное min-height: 100vh , и оно расширяется при рендеринге дочерних элементов. Мне нравится идея здесь, особенно простое% решение.

2. Проверьте мой отредактированный ответ. Вероятно, причиной здесь является 100vh. Вместо этого вы можете попробовать использовать процентную высоту, иначе вам понадобится прослушиватель изменения размера окна.

3. Да, я безуспешно пробовал% решение, StarContainer высота, похоже, устанавливается на основе немедленного рендеринга Skillset компонента, который, по-видимому, затем корректирует свою высоту, чтобы приспособить другие элементы в нем для мобильных устройств. Я решил, что лучше всего просто добавить 200 пикселей к высоте контейнера star и увеличить z-индекс содержимого ниже skillset, чтобы случайные звезды не отображались ниже, чем предполагалось. Не самое элегантное решение, но оно работает!