1

我的用例是:我有一个网站编辑器和一个可供用户使用的网页列表。此列表中的每一页都由一个缩略图表示。每次用户使用编辑器对页面进行更改时,都必须更新相应站点的缩略图以反映更改。我正在做的方式是在页面中安装一个 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。因为传递给 html2canvas 的元素的 ownerDocument 为 null 并且它没有属性:devicePixelRation、innerWidth、innerHeight、pageYOffset 和 pageXOffset。据我了解,这是因为节点元素不是 DOM 的一部分。

现在,我的问题是:

1)有没有办法使用 html2canvas 解决这个问题?

2)有没有其他方法可以在浏览器中截取 React 组件的屏幕截图,而无需在 DOM 中安装组件?

先感谢您!!

4

2 回答 2

0

将反应元素设置为 z-index 和底部 -9999px

于 2020-10-30T12:06:14.830 回答
0

对于第 1 点:

为什么不安装组件,然后在处理后删除 ref 中的组件?(也可以在 ComponentDidMount 中完成,但 ref 会在 DidMount 之前)这是执行下载的最标准解决方案(创建一个标签并单击然后将其删除)

这是使用 ref 回调的示例未经测试的代码

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#componentdidmount

来自 react 的 componentDidMount() 文档部分:“但是,当您需要在渲染取决于其大小或位置的东西之前测量 DOM 节点时,对于模态和工具提示之类的情况,它可能是必要的。”

这清楚地表明您只能在安装节点后获得节点的测量结果。

于 2019-01-30T08:09:06.757 回答