Как отредактировать полученный элемент JSX, чтобы прикрепить опору к любому элементу img внутри него? - PullRequest
0 голосов
/ 04 октября 2019

Я хочу иметь возможность добавить пропозицию onLoad / onAbort к любому элементу изображения или видео внутри элемента JSX, переданного моей функции.

Я создаю компонент галереи, который принимает элементы JSX и отображает ихв выбранном образце. Идея состоит в том, что любой элемент JSX может быть передан, и он будет отформатирован и отображен. Для того, чтобы это работало должным образом, особенно алгоритмы сортировки, которые выполняют несколько проходов, мне нужно знать, когда изображения и видео были загружены и приняты в их исходных разрешениях, чтобы я мог масштабировать их и сохранять соотношения. Для этого я хочу прикрепить свойство onload и onabort к каждому изображению, содержащемуся в элементе JSX, передаваемом в мою функцию, которая обновляет состояние моего компонента, сообщая компоненту, что изображение загружено.

Я не уверен, как это сделать, потому что нет ограничений на структуру входящего элемента JSX. Он может иметь любой уровень вложенности, и изображение или видео могут находиться где угодно внутри этой структуры. Если бы я делал это пост-рендер, я бы сделал:

   //gridRef.current is the grid element ref I get through useRef()
   const images = gridRef.current.querySelectorAll('img');
   images.forEach((image, index) => {
      if (image.complete) //mark current image as already loaded
      else {
         image.onload = () => {
            //mark current image as loaded after it loads
         };
         image.onabort = () => {
            //mark current image as loaded after it aborts
         };
         image.onerror = () => {
            //mark current image as loaded after it errors out
         };
         //mark current image as not loaded yet
      }
   });

И то же самое для видео. Однако я не хочу делать это после рендеринга, потому что изображение может загружаться после проверки image.complete и перед подключением слушателя, что может вызвать ошибку. Было бы гораздо более естественно сделать это еще до рендеринга элемента, но как?

Я бы хотел одно из следующего:

1) Нечто похожее на свойство image.complete, котороесообщает, загружены ли все потомки элементов, поэтому, если бы я использовал его в своем элементе сетки, он вернул бы true только после загрузки всех изображений во всех узлах-потомках. Тогда я мог бы выполнить эту проверку после рендеринга, и мне не нужно было бы редактировать JSX.

2) Способ поиска по иерархии элементов JSX и извлечения, а затем редактирования всех элементов img и video.

3) Свойство, которое запускает функцию, когда загружены все компоненты-потомки.

4) Все остальное, что достигает тех же целей.

Ответы [ 2 ]

1 голос
/ 04 октября 2019

Одно из решений, которое я сейчас использую, состоит в том, чтобы просто иметь рекурсивный тайм-аут, который просматривает все изображения, извлеченные с помощью

   const images = gridRef.current.querySelectorAll('img');

, и проверяет image.complete для каждого и, если они всеtrue он вызывает мою функцию сортировки, если нет, то вызывает сам и проверяет снова после истечения времени ожидания. Он работает достаточно хорошо для изображений, но у элемента видео нет .complete prop.

edit: у видео есть .readyState prop, который отлично работает.

0 голосов
/ 04 октября 2019

Вы можете клонировать элемент, а затем рекурсивно клонировать его дочерние элементы. Добавьте реквизиты, которые вы хотите, прежде чем клонировать дочерние элементы, основываясь на их типах, чтобы сделать это пост-рендерингом. Пример функции:

function editJSX(Component, newProps = {}) {  
  return React.cloneElement(Component, newProps, React.Children.map(Component.props.children, c => {
    let myProps = {};
    if(c.type === "img") {      
      myProps =  {onLoad: handleOnLoad};
    }
    return editJSX(c,myProps); // recursion
  }));
}

Полная демонстрация с проверкой всех загружаемых изображений: https://codesandbox.io/embed/bold-lalande-uhymj

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...