Как сделать снимок экрана с компонента React, не монтируя его в DOM?

Мой пример использования: у меня есть редактор веб-сайта и список доступных веб-страниц для пользователей. Каждая страница в этом списке представлена ​​миниатюрой. Каждый раз, когда пользователь вносит изменения в страницу с помощью редактора, эскиз соответствующего сайта должен обновляться, чтобы отразить это изменение. Я делаю это, монтируя компонент ThumbnailSandbox на странице, передавая реквизиты из хранилища Redux, а затем используя dom-to-png, чтобы создать скриншот и использовать его в списке. Но я хотел сделать это, не устанавливая компонент на странице, потому что я думаю, что это было бы более чистое решение и с меньшими шансами быть затронутым другими взаимодействиями, происходящими. Итак, я создал CodeSanbox, чтобы проиллюстрировать, чего я пытаюсь достичь.

Моя логика такова:

import React from "react";
import ReactDOMServer from "react-dom/server";
import html2canvas from "html2canvas";
import MyComp from "./component.jsx";

export const createScrenshot = () => {
  const el = (
    <div>
      test component <MyComp />
    </div>
  );

  const markup = ReactDOMServer.renderToString(el);
  let doc = new DOMParser().parseFromString(markup, "text/html");
  let target = doc.body.getElementsByClassName("my-comp")[0];

  console.log(markup, target);

  html2canvas(target, {
    useCORS: true,
    allowTaint: true,
    scale: 1,
    width: 500,
    height: 500,
    x: 0,
    y: 0,
    logging: true,
    windowWidth: 500,
    windowHeight: 500
  })
    .then(function(canvas) {
      console.log(">> ", canvas);
    })
    .catch(error => {
      console.log(error);
    });
};

Итак, я передаю компонент в ReactDOM, затем создаю узел DOM, используя строку из первого шага, и передаю узел в html2canvas. Но в этот момент я получаю ошибку Uncaught TypeError: Cannot read property 'pageXOffset' of null, Поскольку ownerDocument элемента, передаваемого в html2canvas, имеет значение null и не имеет свойств: devicePixelRation, innerWidth, innerHeight, pageYOffset и pageXOffset. Как я понимаю, это потому, что элемент узла не является частью DOM.

Теперь мои вопросы:

1) Есть ли способ решить эту проблему с помощью html2canvas?

2) Есть ли другой способ сделать скриншот компонента React в браузере, не монтируя компонент в DOM?

Заранее спасибо!!

1 ответ

Для пункта 1:

Почему бы вам не смонтировать компонент, а затем после обработки удалить компонент в ссылке? (может быть сделано и в ComponentDidMount, но ref должен предшествовать DidMount) Это наиболее стандартное решение для загрузки (создайте тег, нажмите, а затем удалите его)

Это пример непроверенного кода с использованием ref call back

export class CreateScrenshot extends React.Component {
    constructor() {
        super() {
            this._reactRef = this._reactRef.bind(this);
            this.state = {
                removeNode: false
            };
        }
    }

    _reactRef(node) {
        if(node) {
            // your html2Canvas handling and in the returned promise remove the node by
            this.setState({removeNode: true});
        }
    }

    render() {
        let childComponent = null;
        if(!this.state.removeNode) {
            {/*pass the ref of the child node to the parent component using the ref callback*/}
            childComponent =  (
                <div>
                    test component <MyComp refCallBack={this._reactRef}/>
                </div>
            );
        }
        return childComponent;
    }
}

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

Для пункта 2: https://reactjs.org/docs/react-component.html

Из раздела doc реагирования componentDidMount(): "Однако это может быть необходимо для случаев, таких как модалы и всплывающие подсказки, когда вам нужно измерить узел DOM перед рендерингом чего-либо, зависящего от его размера или положения".

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

Установите элемент реакции на z-index и снизу -9999 пикселей

Другие вопросы по тегам