有一种新玩法:将DOM对象转换成图片,很神奇,很神奇,很神奇!
我们要做的,就是将DOM的内容原原本本复制,并绘制成图片。svg的foreignObject元素可以包含html片段,这样就可以将整个DOM片段转换成svg。
然后我们可以有两个选择,第一是将svg插入到一个div中,或者将svg绘制到canvas。svg相对于canvas来说,更清晰。废话少说,上代码:
<html> <body> <script> // dom const div = document.createElement('div'); div.innerHTML = `<div> <h4>svg:</h4> <div id="svg"></div> </div> <div> <h4>canvas:</h4> <canvas id="canvas" style="width: 200px; height: 200px; zoom: .5;" width="100" height="100"></canvas> </div>`; document.body.appendChild(div); // 图片 const html = `<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> <foreignObject width="100%" height="100%"> <div xmlns="http://www.w3.org/1999/xhtml">Hello, world!</div> </foreignObject> </svg>`; document.getElementById('svg').innerHTML = html; const img = new Image(); const svg = new Blob(html.split(''), { type: 'image/svg+xml;charset=utf-8' }); const url = window.URL.createObjectURL(svg); function imgLoad(event){ let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); ctx.scale(2, 2); window.URL.revokeObjectURL(url); } img.src = url; img.addEventListener('load', imgLoad, false); </script> </body></html>
不过要注意的是,在svg里面的class
是无效的,样式只有style=“key: value;”
才能生效。可以使用window.getComputedStyle
来获取DOM的样式。如果嫌麻烦,还可以使用html2canvas库。
svg内dom节点的xmlns
属性不能省略。
最后来个简单canvas的Demo:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <style> body { margin: 0; } .article { box-sizing: border-box; margin: 0 auto; padding: 10px; width: 300px; height: 560px; border: 1px solid #ddd; border-radius: 5px; background-color: #fff; } .article-title { font-size: 16px; } .article-secondtitle { font-size: 12px; color: #7e7e7e; } .article-title, .article-secondtitle { text-align: center; } .article p { font-size: 14px; } .canvas { position: fixed; top: 0; left: 50%; display: block; width: 300px; height: 560px; margin: 0 0 0 -152px; border: 1px solid #ddd; border-radius: 5px; } @keyframes body1{ 0% { transform: rotateZ(0) rotateY(0) scale(1) ; } 50% { transform: rotateZ(180deg) rotateY(0) scale(.9) ; } 100% { transform: rotateZ(360deg) rotateY(180deg) scale(0); } } .animate { animation-name: body1; animation-timing-function: linear; animation-fill-mode: forwards; } .ani0 { animation-delay: 1s; animation-duration: 2s; z-index: 4; } .ani1 { animation-delay: 1.4s; animation-duration: 1.7s; z-index: 3; } .ani2 { animation-delay: 1.8s; animation-duration: 1.4s; z-index: 2; } .ani3 { animation-delay: 2.2s; animation-duration: 1.1s; z-index: 1; } </style> </head> <body> <article class="article" id="article"> <h1 class="article-title">将进酒·君不见黄河之水天上来</h1> <h6 class="article-secondtitle">[唐] 李白</h6> <p>君不见黄河之水天上来,奔流到海不复回。</p> <p>君不见高堂明镜悲白发,朝如青丝暮成雪。</p> <p>人生得意须尽欢,莫使金樽空对月。</p> <p>天生我材必有用,千金散尽还复来。</p> <p>烹羊宰牛且为乐,会须一饮三百杯。</p> <p>岑夫子,丹丘生,将进酒,杯莫停。</p> <p>与君歌一曲,请君为我侧耳听。</p> <p>钟鼓馔玉不足贵,但愿长醉不复醒。</p> <p>古来圣贤皆寂寞,惟有饮者留其名。</p> <p>陈王昔时宴平乐,斗酒十千恣欢谑。</p> <p>主人何为言少钱,径须沽取对君酌。</p> <p>五花马,千金裘,</p> <p>呼儿将出换美酒,与尔同销万古愁。</p> </article> <canvas class="canvas animate ani0" id="canvas_0" width="300" height="560"></canvas> <canvas class="canvas animate ani1" id="canvas_1" width="300" height="560"></canvas> <canvas class="canvas animate ani2" id="canvas_2" width="300" height="560"></canvas> <canvas class="canvas animate ani3" id="canvas_3" width="300" height="560"></canvas> <!-- 特效代码 --> <script> function style2String(node){ const css = window.getComputedStyle(node); let style = ''; style += `padding: ${ css.padding }; `; style += `width: ${ css.width }; `; style += `font-size: ${ css.fontSize }; `; style += `font-family: ${ css.fontFamily.replace(/"/g, '') }; `; style += `border-radius: ${ css.borderRadius }; `; style += `color: ${ css.color }; `; style += `text-align: ${ css.textAlign }; `; style += `background-color: ${ css.backgroundColor }; `; return style; } function html2Text(node){ // 节点 let txt = ''; if(node.nodeName !== '#text'){ const nodeName = node.nodeName.toLowerCase(); const style = style2String(node); txt += `<${ nodeName } style="${ style }">`; // 子节点 const childNodes = node.childNodes; for(let i = 0, j = childNodes.length; i < j; i++){ txt += html2Text(childNodes[i]); } txt += `</${ nodeName }>`; }else{ txt += node.data; } return txt; } </script> <script> const article = document.getElementById('article'); const html = `<svg width="300" height="560px" xmlns="http://www.w3.org/2000/svg"> <foreignObject width="100%" height="100%"> <div xmlns="http://www.w3.org/1999/xhtml">${ html2Text(article) }</div> </foreignObject> </svg>`; // nodeName const img = new Image(); const svg = new Blob(html.split(''), { type: 'image/svg+xml;charset=utf-8' }); const url = window.URL.createObjectURL(svg); function onCanvasAnimationEnd(event){ this.removeEventListener('animationend', onCanvasAnimationEnd); const father = this.parentNode; father.removeChild(this); } function imgLoad(event){ for(let i = 0; i < 4; i++){ let canvas = document.getElementById('canvas_' + i); let ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); canvas.addEventListener('animationend', onCanvasAnimationEnd, false); canvas = ctx = null; } window.URL.revokeObjectURL(url); } img.src = url; img.addEventListener('load', imgLoad, false); </script> </body> </html>
好吧,SVG版的DEMO也可以哟。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <style> body { margin: 0; } .article { box-sizing: border-box; margin: 0 auto; padding: 10px; width: 300px; height: 560px; border: 1px solid #ddd; border-radius: 5px; background-color: #fff; } .article-title { font-size: 16px; } .article-secondtitle { font-size: 12px; color: #7e7e7e; } .article-title, .article-secondtitle { text-align: center; } .article p { font-size: 14px; } .svg { position: fixed; top: 0; left: 50%; display: block; width: 300px; height: 560px; margin: 0 0 0 -152px; border: 1px solid #ddd; border-radius: 5px; } @keyframes body1{ 0% { transform: rotateZ(0) rotateY(0) scale(1) ; } 50% { transform: rotateZ(180deg) rotateY(0) scale(.9) ; } 100% { transform: rotateZ(360deg) rotateY(180deg) scale(0); } } .animate { animation-name: body1; animation-timing-function: linear; animation-fill-mode: forwards; } .ani0 { animation-delay: 1s; animation-duration: 2s; z-index: 4; } .ani1 { animation-delay: 1.4s; animation-duration: 1.7s; z-index: 3; } .ani2 { animation-delay: 1.8s; animation-duration: 1.4s; z-index: 2; } .ani3 { animation-delay: 2.2s; animation-duration: 1.1s; z-index: 1; } </style> </head> <body> <article class="article" id="article"> <h1 class="article-title">将进酒·君不见黄河之水天上来</h1> <h6 class="article-secondtitle">[唐] 李白</h6> <p>君不见黄河之水天上来,奔流到海不复回。</p> <p>君不见高堂明镜悲白发,朝如青丝暮成雪。</p> <p>人生得意须尽欢,莫使金樽空对月。</p> <p>天生我材必有用,千金散尽还复来。</p> <p>烹羊宰牛且为乐,会须一饮三百杯。</p> <p>岑夫子,丹丘生,将进酒,杯莫停。</p> <p>与君歌一曲,请君为我侧耳听。</p> <p>钟鼓馔玉不足贵,但愿长醉不复醒。</p> <p>古来圣贤皆寂寞,惟有饮者留其名。</p> <p>陈王昔时宴平乐,斗酒十千恣欢谑。</p> <p>主人何为言少钱,径须沽取对君酌。</p> <p>五花马,千金裘,</p> <p>呼儿将出换美酒,与尔同销万古愁。</p> </article> <!-- 特效代码 --> <script> function style2String(node){ const css = window.getComputedStyle(node); let style = ''; style += `padding: ${ css.padding }; `; style += `width: ${ css.width }; `; style += `font-size: ${ css.fontSize }; `; style += `font-family: ${ css.fontFamily.replace(/"/g, '') }; `; style += `border-radius: ${ css.borderRadius }; `; style += `color: ${ css.color }; `; style += `text-align: ${ css.textAlign }; `; style += `background-color: ${ css.backgroundColor }; `; return style; } function html2Text(node){ // 节点 let txt = ''; if(node.nodeName !== '#text'){ const nodeName = node.nodeName.toLowerCase(); const style = style2String(node); txt += `<${ nodeName } style="${ style }">`; // 子节点 const childNodes = node.childNodes; for(let i = 0, j = childNodes.length; i < j; i++){ txt += html2Text(childNodes[i]); } txt += `</${ nodeName }>`; }else{ txt += node.data; } return txt; } </script> <script> const body = document.body; const article = document.getElementById('article'); const html = `<svg width="300" height="560px" xmlns="http://www.w3.org/2000/svg"> <foreignObject width="100%" height="100%"> <div xmlns="http://www.w3.org/1999/xhtml">${ html2Text(article) }</div> </foreignObject> </svg>`; function onCanvasAnimationEnd(event){ this.removeEventListener('animationend', onCanvasAnimationEnd); const father = this.parentNode; father.removeChild(this); } for(let i = 0; i < 4; i++){ let div = document.createElement('div'); div.innerHTML = html; div.className = `svg animate ani${ i }`; div.addEventListener('animationend', onCanvasAnimationEnd, true); body.appendChild(div); div = null; } </script> </body> </html>
OVER,觉得很不错的,你可以学习下咯
网友评论文明上网理性发言 已有0人参与
发表评论: