Heim > Web-Frontend > js-Tutorial > Hauptteil

JavaScript implementiert die Screenshot-Funktion

巴扎黑
Freigeben: 2017-08-14 14:07:38
Original
1867 Leute haben es durchsucht

Ich finde die Idee, JS zum Erstellen von Screenshots zu verwenden, sehr lächerlich. Erstens hat JS keine Berechtigung, die Screenshot-Funktion des Betriebssystems aufzurufen Nach einigem Hin und Her habe ich einige Ideen zum Implementierungscode der js-Screenshot-Funktion erhalten.

Ich habe kürzlich an der Entwicklung teilgenommen Verwandte Seiten von NetEase Hearthstone Box und arbeite an einer Seite zum Teilen von Kartengruppen (Adresse: Hearthstone Box Kartengruppen-Sharing). Es besteht eine Anforderung: Benutzer können diese Kartengruppe in Form von Bildern mit Freunden teilen. Der ursprüngliche Ansatz bestand darin, die Seite mithilfe des Servers in ein Bild umzuwandeln und dann die Bildadresse an das Frontend zurückzugeben. Nun, das ist ziemlich gut, und der Server kann die konvertierten Bilder auch zwischenspeichern und die nächste Anfrage kann die Bildadresse direkt zurückgeben. Daran ist grundsätzlich nichts auszusetzen. Es tritt jedoch gelegentlich ein Problem auf, das nicht mit dem Seiteninhalt übereinstimmt, und manchmal fehlen Inhalte. Die PM-Schwester ist sehr unzufrieden und sagt, dass dieses Problem gelöst werden muss. Wie auch immer, die Schnittstelle zum Konvertieren von Seiten in Bilder läuft im Hintergrund, das geht mich nichts an! Gerade als ich insgeheim glücklich war, passierte etwas Tragisches. Ein Kollege im Hintergrund sagte, dass die Serverkonvertierung manchmal instabil sei, weil einige Inhalte auf der Seite asynchron geladen würden Asynchron gerenderte Inhalte können nicht abgefangen werden. Um es ganz klar auszudrücken: Er hat keine Möglichkeit, dieses Problem zu lösen. Wer hat dem Frontend gesagt, dass es asynchrones Rendering verwenden soll? Schließlich bat mich der Leiter, zu versuchen, JS direkt zum Erstellen von Screenshots zu verwenden, was nicht nur die Belastung des Servers verringern, sondern auch den oben genannten Fehler beheben würde.

Zuerst fand ich die Idee, JS zum Erstellen von Screenshots zu verwenden, sehr lächerlich (Schuld daran ist meine Unwissenheit, das Frontend hat sich in den letzten Jahren zu schnell entwickelt): Erstens tut es JS Sie haben keine Berechtigung, die Screenshot-Funktion des Betriebssystems aufzurufen, und zweitens stellt der Browser (BOM) auch keine entsprechende Screenshot-Schnittstelle zur Verfügung. Was soll ich tun? Was soll ich tun? Bei Fragen wenden Sie sich bitte an Google. Dann habe ich nach „JS html to png“ gesucht und dann Folgendes gefunden: „render-html-to-an-image“. Mir kommen langsam einige Ideen, in der Antwort wurde erwähnt, dass man DOM in Canvas konvertieren kann, nicht wahr? Es ist wieder Canvas! Ich konnte nicht anders, als aufgeregt zu sein. Es war wirklich schwierig, einen Ausweg aus den Bergen und Flüssen zu finden, aber es gab immer noch eine glänzende Zukunft in einem anderen Dorf! Dann habe ich nach „dom to canvas“ gesucht und bin auf das bekannte MDN-Dokument „Drawing_DOM_objects_into_a_canvas“ gestoßen. Dann begann ich, das Dokument ernsthaft zu lesen. Wie am Anfang des Dokuments erwähnt, können Sie DOM nicht in Canvas konvertieren, aber Sie können DOM in SVG konvertieren und dann das SVG in den Canvas zeichnen. Manche Leute fragen sich vielleicht: Warum müssen wir zuerst dom in SVG konvertieren? Dies kann daran liegen, dass SVG die XML-Darstellung verwendet und seine Struktur mit der von DOM übereinstimmt.
Das Folgende ist die Schritt-für-Schritt-Anleitung aus dem offiziellen Dokument:

1. Der Medientyp „Blob“ muss „image/svg+xml“ sein

Ein SVG-Element ist erforderlich

3. Fügen Sie ein foreignObject -Element in das SVG-Element

ein. 4. Fügen Sie HTML, das der Spezifikation entspricht, in das ForeignObject-Element

ein. Das Konvertieren von Dom in Canvas ist genauso einfach wie oben beschrieben. Das Folgende ist eine einfache Demo im Dokument:


<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
</head>
<body>
<canvas id="canvas" style="border:2px solid black;" width="200" height="200">
</canvas>
<script>
 var canvas = document.getElementById(&#39;canvas&#39;);
 var ctx = canvas.getContext(&#39;2d&#39;);
 var data = &#39;<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">&#39; +
  &#39;<foreignObject width="100%" height="100%">&#39; +
  &#39;<p xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">&#39; +
  &#39;<em>I</em> like &#39; +
  &#39;<span style="color:white; text-shadow:0 0 2px blue;">&#39; +
  &#39;cheese</span>&#39; +
  &#39;</p>&#39; +
  &#39;</foreignObject>&#39; +
  &#39;</svg>&#39;;
 var DOMURL = window.URL || window.webkitURL || window;
 var img = new Image();
 var svg = new Blob([data], {type: &#39;image/svg+xml&#39;});
 var url = DOMURL.createObjectURL(svg);
 img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
 }
 img.src = url;
</script>
</body>
</html>
Nach dem Login kopieren

Wow, es ist so cool, dass es im Browser erscheint. Es gibt zwei Zeilen mit künstlerischen Worten!

Nun, es stellt sich heraus, dass die Konvertierung von Dom in Canvas so einfach ist? Dann verwende ich document.body.innerHTML , um das gesamte DOM im Textkörper herauszunehmen und in das ForeignObject-Element einzufügen. Ist das nicht in Ordnung und die gesamte Seite wird erfasst?

Die Demo ist nur eine Hello World, aber die Dom-Struktur im eigentlichen Projekt ist viel komplizierter. Beispielsweise entsprechen externe Stylesheets, Bilder und einige Tags möglicherweise nicht der XML Spezifikation (z. B. Fehlendes schließendes Tag usw.). Hier ist ein einfaches Beispiel. .container verwendet keine Inline-Stile, sondern ist im Stil-Tag definiert. Nach der Konvertierung in ein Bild wird der Stil nicht wirksam.


<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
 <style>
  .container {
   color: red;
  }
 </style>
</head>
<body>
<p class="container" >
 Hello World!
</p>
<canvas id="canvas" style="border:2px solid black;" width=200" height="200">
</canvas>
<script>
 var canvas = document.getElementById(&#39;canvas&#39;);
 var ctx = canvas.getContext(&#39;2d&#39;);
 var data = &#39;<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">&#39; +
  &#39;<foreignObject width="100%" height="100%">&#39; +
  &#39;<p xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">&#39; +
  document.querySelector(&#39;.container&#39;).innerHTML +
  &#39;</p>&#39; +
  &#39;</foreignObject>&#39; +
  &#39;</svg>&#39;;
 var DOMURL = window.URL || window.webkitURL || window;
 var img = new Image();
 var svg = new Blob([data], {type: &#39;image/svg+xml&#39;});
 var url = DOMURL.createObjectURL(svg);
 img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
 }
 img.src = url;
</script>
</body>
</html>
Nach dem Login kopieren

Da externe Stile nicht wirksam werden, können wir alle Dom-Elemente über JS durchlaufen und alle Stile über das element.style-Objekt zu Inline-Stilen hinzufügen. Diese Idee hört sich gut an, aber ich kann wirklich nicht die Funktion schreiben, die externe Stile in Inline-Stile umwandelt. Die Nachfrage ist gering und ich habe nicht viel Zeit zum Herumspielen, deshalb möchte ich nach fertigen Bibliotheken suchen. Also ging ich noch einmal zu Google. Glücklicherweise habe ich sofort eine Bibliothek namens html2canvas gefunden. Es ist eine großartige Bibliothek, sehr leistungsfähig, aber sehr einfach zu verwenden. Mit einer so einfachen Methode kann ich einen Screenshot meiner gesamten Seite erstellen:


function convertHtml2Canvas() {
  html2canvas(document.body, {
   allowTaint: false,
   taintTest: true
  }).then(function(canvas) {
   document.body.appendChild(canvas);
  }).catch(function(e) {
   console.error(&#39;error&#39;, e);
  });
 }
Nach dem Login kopieren

目前还有一个问题,就是这种方法默认是把整个页面截取下来的(就是说,会以你的innerHeight和innerWidth为边界,会存在大量的空白),可是,我的卡组只是占了页面的一小部分,我只想要卡组的部分啊。其实已经有了canvas就好办了,我们可以对它进行处理啊。大概思路是:1.把上面得到的canvas对象转成Blob并放到一个img元素。然后再把img.src绘制到canvas里面。这时候调用canvas.drawImage方法就可以截取我们想要的内容了。下面的两个函数分别是把canvas转成image以及反过来把image转成canvas。


// Converts canvas to an image
 function convertCanvasToImage(canvas) {
  var image = new Image();
  image.src = canvas.toDataURL("image/png", 0.1);
  return image;
 }
 // Converts image to canvas; returns new canvas element
 function convertImageToCanvas(image, startX, startY, width, height) {
  var canvas = document.createElement("canvas");
  canvas.width = width;
  canvas.height = height;
  canvas.getContext("2d").drawImage(image, startX, startY, width, height, 0, 0, width, height);
  return canvas;
 }
Nach dem Login kopieren

然后,再把我们上面的写的 convertHtml2Canvas 改成下面的:


function convertHtml2Canvas() {
  html2canvas(document.body, {
   allowTaint: false,
   taintTest: true
  }).then(function(canvas) {
   var img = convertCanvasToImage(canvas);
   document.body.appendChild(img);
   img.onload = function() {
    img.onload = null;
    canvas = convertImageToCanvas(img, 0, 0, 384, 696);
    img.src = convertCanvasToImage(canvas).src;
    $(img).css({
     display: &#39;block&#39;,
     position: &#39;absolute&#39;,
     top: 0,
     left: 400 + &#39;px&#39;
    });
   }
  }).catch(function(e) {
   console.error(&#39;error&#39;, e);
  });
 }
Nach dem Login kopieren

这时候就可以把它的页面的某部分内容进行截取下来了。效果如卡组分享测试页面。页面左边部分是DOM结构的,右边部分是则是使用html2canvas转换出来的图片。长得一模一样,毫无毛病哈。

关于JS页面截图的就写到这里啦,因为也只刚刚接触,很多东西也理解得不到位,欢迎各大神指点。后面会深入学习一下html2canvas的源码,进一步理解dom to canvas的原理。

Das obige ist der detaillierte Inhalt vonJavaScript implementiert die Screenshot-Funktion. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!