In this H5 activity, I met a requirement that I click button to generate HTML pictures and hold down the save function. Since the structure of HTML is complicated, it is relatively more workload to draw directly with canvas, so HTML2Canvas is used. Html2canvas is relatively easy to use. But there are many holes

The age-old cross-domain problem

When it comes to cross-domain problems, you should have encountered this problem as long as you enter the pit of converting canvas toDataURL into images. If you do not carry out cross-domain processing to generate images that cannot cross domain will be blank processed. There is no good solution. The image server needs to be configured with Access-Control-Allow-Origin. Since the development build and JS of the company are done by two teams, the image address of the build team is not cross-domain, and all the image Settings on the page are in the form of background image. I did the following to deal with this problem

  1. Download the previous build image and re-upload it to the CND server that supports cross-domain
  2. Rewrite the HTML CSS style background image that needs to be generated

This is not the end of course. Configure HTML2Canvas

html2canvas(dom, {
        backgroundColor: null,
        canvas,
        //allowTaint: true,
        useCORS: true
    })
Copy the code

The useCORS setting allows cross-domain. AllowTaint also allows cross-domain, but this cross-domain setting only allows you to generate canvas across domains, but it still can’t convert canvas into images. To solve the cross-domain problem of toDataURL, useCORS is also needed. But these two properties cannot coexist

The resulting image is blurry

Set scale to double and go straight to the code

Function DPR() {if (window.devicepixelRatio && window.devicepixelRatio > 1) {/ function DPR() {if (window.devicepixelRatio && window.devicepixelRatio > 1) { return window.devicePixelRatio; } return 1; }... Const width = parseValue(box-width); const height = parseValue(box.height); // Get pixel ratio const scaleBy = DPR()*2; Var canvas = document.createElement('canvas'); // Set canvas element property width to DOM node width * pixel ratio canvas. Width = width * scaleBy; canvas.height = height * scaleBy; // Set canvas CSS width to DOM node width canvas.style.width = '${width}px'; canvas.style.height = `${height}px`; // Get the brush const context = canvas.getContext('2d'); Context. scale(scaleBy, scaleBy); // imageSmoothingEnabled Canvas 2D API is used to set whether the image is smooth or not. True means that the image is smooth (default), false means that the image is not smooth. The default resizing algorithm will blur the image and destroy the original pixels of the image. If so, set the property value to false. context.mozImageSmoothingEnabled = false; context.webkitImageSmoothingEnabled = false; context.msImageSmoothingEnabled = false; context.imageSmoothingEnabled = false; . Html2canvas (dom, {backgroundColor: null, canvas, width: width, // set width height: height, // set height scale: ScaleBy,// set scaleBy useCORS: true})Copy the code

The Sprite image used in the process is most prone to blur, so the image needs to use a 2x image

HTML flash appears during image generation

Maybe this title doesn’t describe the problem very well. I will describe the problem first, because html2Canvas generates the image of the HTML must be real, or generate canvas blank. If you need to generate HTML, you cannot set it to disabled: None; visibility: hidden; Such attributes. Therefore, it indicates that dom node rendering must be completed in the process of calling HTML2Canvas to generate canvas. So this will lead to flash of the original HTML in the canvas generation. This problem is actually easier to solve by using a small trick, using the top attribute to remove the HTML view top:100% of course, there are many solutions, I am using this one

Dynamic rendering of HTML to canvas will cause style errors

This problem, itself needs to generate a part of the HTML is a wheel cast graph, so the HTML DOM will render dynamically, the solution is very simple, cancel the wheel cast graph, directly with V-IF (note: project using VUE development) decision HTML rendering, cancel wheel cast

Background-repeat: no-repeat; Does not take effect, resulting in duplicate images

Background-repeat: no-repeat; background-repeat: no-repeat; But there will be about 1 pixel repetition at the bottom of the image. Since the root cause was not found, the most direct solution was used to directly increase the image height by 2 pixels, which successfully avoided this problem. (ha ha ha ha, I was a devil of a genius opportunistic)

Html2canvas does not support display: -webkit-box

Because there is a paragraph of code that requires an ellipsis at the end of multiple lines, the following CSS appears

    display: -webkit-box;
    overflow: hidden;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    text-overflow: ellipsis;
Copy the code

In HTML2Canvas, the value of display in CSS is mapped to a number. In the mapping table below, as long as the flex mapping value is found, there is no –webkit-flex mapping value, so -webkit-flex is mapped to display. NONE. As a result, isVisible’s computed value returns false, resulting in an inability to generate the desired canvas

The solution does not use flex layout, JS text overflow, this scheme is limited to the specific number of words, so more limited, we have a good solution welcome to add CSS

Height: 2 times the line - height; /* Change as needed */ display:inline-block;Copy the code

js

contentText(num){
        const ellipsis = oldContentText.length > num?'... ':' '
        return oldContentText.slice(0,num) + ellipsis
  }
Copy the code