Prelude
In order to improve the runtime problem feedback system, user voice related functions were developed a long time ago. One of the modules is to generate screenshots of the current picture and upload it. As an old developer, you must canvans do it. You must find a ready-made plug-in htmlcavans and directly introduce it. This is not so easy. After the final implementation, you find yourself too young and all kinds of abysses and pits. Here is a record of the way to step on the pit.
problem
- 1. img tag generation failed when generating pictures, and the display is blank
- 2. Pop up component screenshot with pure black or white background
- 3. Iframe production failed, and the iframe area is blank after the screenshot
Next, analyze the solutions one by one
img tag generation failed when generating pictures, and the display is blank
Various settings of htmlcavans according to the online tutorial failed to solve this problem. So the sword moves sideways. When generating canvans, copy a DOM, and then add a backgroundImg attribute to the img tag under the dom. The reason for copy is to prevent updates from affecting the original view and control the scope of influence. The following code is directly added
let cloneDome = document.cloneNode(true); let ImgList = cloneDome.querySelectorAll("img"); //Set the background to the implementation screenshot for (let i = 0; i < ImgList.length; i++) { let src = ImgList[i].getAttribute("src"); ImgList[i].style.backgroundImage = ` url(${src})`; ImgList[i].style.backgroundSize = "100%"; } return new html2canvas(cloneDome.body, { .... })
Pop up component screenshots with pure black or white background (use with caution!)
This problem also plagued for a period of time. After troubleshooting, there was a problem with the support of the opacity attribute. The processing scheme also operated on the dom of copy when generating pictures, and converted it to rgba background color to achieve a similar transparency effect. However, this scheme may be miskilled and used cautiously
let cloneDome = document.cloneNode(true); //Due to the risk of batch processing, only dom that needs to be processed is processed here if(cloneDome.querySelector("******")){ cloneDome.querySelector("******").style.opacity = 1; cloneDome.querySelector("******").style.backgroundColor = "rgba(0,0,0,0.5)"; return new html2canvas(cloneDome.body, { .... }) }
Iframe production failed, and the iframe area is blank after the screenshot
Iframe failed to generate images. At first, we thought it was a cross domain problem caused by different domains, but it still failed after adjusting the domain. The problem came back. After discussing with group Daniel, we decided to adopt a more coquettish routine. The specific implementation is: before generating images, if they are stored in iframe, the main page sends messages to iframe, generates images from screenshots in iframe and passes them to the main page, and the main page merges images, However, there are some problems in merging pictures. The most difficult problem is how to calculate and obtain the merged position. On second thought, it is not necessary to calculate by yourself. Setting the background picture directly to iframe perfectly solves the most difficult problem of merging position. The code is as follows:
(ps: by default, there is only one iframe in this scheme, and multiple iframes will not be considered temporarily due to performance and other problems. The code can be modified according to the support of multiple iframes.)
//If there is ifram====== wait for the image of ifram to be generated let ifram = cloneDome.querySelector("iframe"); let promiseProxy="" if ( ifram && ifram.getAttribute("src").indexOf("fas.teld.org") != -1 ) { promiseProxy = new Promise((resolve)=>{ window.onmessage = (e) => { if (e.data.type == "ScreenshotResult") { ifram.style.backgroundSize = "100%"; ifram.style.backgroundImage = ` url(${ e.data.data})`; resolve() } }; //If the message fails, it will be released automatically in case of timeout to prevent the page from blocking setTimeout(() => { resolve() }, 10000); }) ifram.contentWindow.postMessage({ type: "Screenshot" }, "*"); } if(promiseProxy){ await promiseProxy } return new html2canvas(cloneDome.body, { .... })