借助SVG forginObject实现DOM转图片实例页面

回到相关文章 »

鼠标经过下面任意区域并点击:

长天
长天
对网文潮流具有极敏锐嗅觉,有丰富写作指导经验。带出血红、猫腻、。。。。

代码:

CSS代码:
.outline {
    outline: 2px solid red;
    outline-offset: -2px;
}
HTML代码:
<div id="cmBox" class="c-m-box">
    <div class="c-m-list">
        <img src="0.jpg" alt="长天" class="c-m-img">
        <div class="c-m-name">长天</div>
        <div class="c-m-title">对网文潮流具有极敏锐嗅觉...</div>
    </div>
</div>
                
JS代码:
// DOM转图片的方法
var domToImg = (function () {
    // 转png需要的canvas对象及其上下文
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');

    // canvas绘制图片元素方法
    var draw = function (img) {
        var width = img.width, height = img.height;
        // canvas绘制
        canvas.width = width;
        canvas.height = height;
        // 画布清除
        context.clearRect(0, 0, width, height);
        // 绘制图片到canvas
        context.drawImage(img, 0, 0);
    };

    // canvas画布绘制的原图片
    var img = new Image();
    // 回调
    var callback = function () {};

    // 图片回调
    img.onload = function () {
        draw(this);
        // 回调方法
        callback();
    };

    var exports = {
        dom: null,
        // DOM变成svg,并作为图片显示
        dom2Svg: function () {
            var dom = this.dom;
            if (!dom) {
                return this;
            }

            // 复制DOM节点
            var cloneDom = dom.cloneNode(true);
            cloneDom.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
            cloneDom.classList.remove('outline');

            // 如果有图片,变成base64
            var imgDom = null;
            if (cloneDom.tagName.toLowerCase() == 'img') {
                imgDom = cloneDom;
            } else {
                // 这里就假设一个图片,多图自己遍历转换下就好了
                imgDom = cloneDom.querySelector('img');
            }

            if (imgDom) {
                draw(imgDom);
                imgDom.src = canvas.toDataURL();
            }

            var htmlSvg = 'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="' + dom.offsetWidth + '" height="' + dom.offsetHeight + '"><foreignObject x="0" y="0" width="100%" height="100%">'+
                new XMLSerializer().serializeToString(cloneDom) +
                document.querySelector('style').outerHTML +
             '</foreignObject></svg>';

             htmlSvg = htmlSvg.replace(/\n/g, '').replace(/\t/g, '').replace(/#/g, '%23');

            // 图片地址显示为DOM转换的svg
            img.src = htmlSvg;

            return this;
        },
        // 作为图片下载,JS前端下载可参考这篇文章:
        // JS前端创建html或json文件并浏览器导出下载 - http://www.zhangxinxu.com/wordpress/?p=6252
        download: function () {
            // 创建隐藏的可下载链接
            var eleLink = document.createElement('a');
            // 下载图片文件名就按照时间戳来
            eleLink.download = 'zxx_png-' + (+new Date() + '').slice(1, 9) + '.png';
            eleLink.style.display = 'none';

            // 触发图片onload是个异步过程,因此,需要在回调中处理
            callback = function () {
                eleLink.href = canvas.toDataURL();
                // 触发点击
                document.body.appendChild(eleLink);
                eleLink.click();
                // 然后移除
                document.body.removeChild(eleLink);
            };

            // dom变图片
            this.dom2Svg();
        }
    };

    return exports;
})();

// 实例页面的交互代码
var eleBox = document.getElementById('cmBox');
// hover outline
eleBox.addEventListener('mouseover', function (event) {
    if (event.target !== this) {
        event.target.classList.add('outline');
    }
});
eleBox.addEventListener('mouseout', function (event) {
    var eleOutline = eleBox.querySelector('.outline');
    if (eleOutline) {
        eleOutline.classList.remove('outline');
    }
});
// 点击并下载图片
eleBox.addEventListener('click', function (event) {
    var eleTarget = event.target;
    if (eleTarget !== this) {
        domToImg.dom = eleTarget;
        domToImg.download();
    }
});