网上偶尔看到的一篇文章,觉得挺有意思的,在此mark一下。其实这种需求可以直接使用相关插件的:html2canvas,源码也容易看懂...
有一种新玩法:将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>
本段代码来自 http://www.jiangweishan.com/article/DOMW123123124124.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>
本段代码来自 http://www.jiangweishan.com/article/DOMW123123124124.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>
本段代码来自 http://www.jiangweishan.com/article/DOMW123123124124.html