前端开发 JS将DOM对象转换成图片

前端电商网站开发周期|网站前端程序制作开发|web前端是网站开发么

前两天看到了一个动画,就琢磨着怎么简单实现一下。
我们要做的,就是将DOM的内容原原本本复制,并绘制成图片。svg的foreignObject元素可以包含html片段,这样就可以将整个DOM片段转换成svg。
然后我们可以有两个选择,第一是将svg插入到一个div中,或者将svg绘制到canvas。svg相对于canvas来说,更清晰。

<!DOCTYPE html>
<html lang=”en”>
<head>
    <meta charset=”UTF-8″>
    <meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
    <meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
    <title>前端快速开发网站:js Dom</title>
</head>
<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属性不能省略。

最后来个简单的Demo:

canvas:

<!DOCTYPE html>
<html lang=”en”>
<head>
    <meta charset=”UTF-8″>
    <title>前端网站开发教程:js</title>
    <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:

<!DOCTYPE html>
<html lang=”en”>
<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>
网站前端开发研究内容|适合新手前端开发的网站|需要前端开发的网站

 

赞(0)
前端开发者 » 前端开发 JS将DOM对象转换成图片
64K

评论 抢沙发

评论前必须登录!