vue使用HTML截图插件html2canvas 对动态载入页面进行截图

2,929 阅读3分钟

场景:

项目需要做一个以HTML作为模板的预览列表,预览列表通过截图的方式进行显示,类似于图片的缩略图。

那为什么不直接使用html解析的方式放置在固定的容器内呢?

容器会对HTML进行解析,例如200px的空间内显示600px宽的html原始页面,显示的布局会被压缩,不是按比例进行解析,至于是否有CSS可以控制HTML,进行类似图片可以按照比例进行显示,没有找到什么好的办法。


查了一些资料都是对本页面进行截图,如果需要结合VUE截图的资料也比较少,主要是涉及到一些对象的取值和设置,费了一些周折。


一、首先按照官方的文档进行安装

官网地址:html2canvas.hertzen.com/


二、新建个html截图组件

命名为:html-capture.vue

<template>    
    <!--<img :src="imgUrl"/>--> 
    <!--这里使用的ElementUI的组件,可换成普通的图片标签-->
    <el-image :src="imgUrl" fit="scale-down" :preview-src-list="srcList">
    <!--preview-src-list 用来点击预览图片 -->    </el-image>    
</template>
<script>
import html2canvas from 'html2canvas'
import HtmlPanel from '@/components/html-panel'
export default {  
    name: 'HtmlCapture',  
    components: {    
        html2canvas
    },  
    props: {    
        htmlUrl: {      
            required: true    
        },    
        width: String,    
        height: String,    
        src: String  
    },  
    data () {    
        return {      
            imgUrl: '',      
            srcList: []    
        }  
    },  
    methods: {    
        // html截图 ,v 将Vue对象传递进方法,截图方法内无法获取Vue的this对象    
        htmlToImg (v) {     
            // 通过创建临时的iframe动态加载页面 实现通过url获取dom      
            var iframe = document.createElement('iframe')      
            iframe.ref = 'htmlLoadFrame'      iframe.src = this.htmlUrl      
            // 隐藏临时iframe   
            document.body.appendChild(iframe)      
            iframe.style.cssText = 'position: absolute; opacity:0; z-index: -9999'      
            // iframe加载完成后触发      
            iframe.onload = function (e) {              
                // 生成iframe中的页面截图        
                html2canvas(iframe.contentDocument.documentElement, {          
                    // 设置截图的背景色,设置为白色背景,预览时不是透明图片          
                    backgroundColor: 'white', 
                    // 如果截图的内容里有图片,可能会有跨域的情况,加上这个参数,解决文件跨域问题      
                    useCORS: true,
                    // 允许跨域(图片跨域相关)            
                    allowTaint: true,        
                    // 是否在渲染前测试图片          
                    taintTest: true,          
                    // 放大倍数,4倍相对文字比较清晰      
                    scale: 4,                 
                    // 设置图片的宽度
                    windowWidth: iframe.contentDocument.documentElement.clientWidth * 2,          
                    width: iframe.contentDocument.documentElement.clientWidth * 2        
                }).then((canvas) => { 
                    // 转换为Base64,将base64赋值给data中的imgUrl变量 
                    // 通过参数传递的Vue对象设置变量值,此处无法直接操作Vue this对象        
                    v.imgUrl = canvas.toDataURL('image/png')  
                    // 赋值给ElementUI预览图片时需要的数组 
                    v.srcList.push(v.imgUrl) 
                    // 截图完成后销毁iframe         
                    iframe.remove()        
                })      
            }   
         } 
        },  
    mounted () {    
        this.htmlToImg(this)  
    }}
</script>
<style>
</style>

三、使用组件

<template>
    <div v-for="el in elData">
      <el-card class="box-card" style="height:300px" shadow="hover">
        <html-capture :htmlUrl="el.url" style="width:100%"></html-capture>
      </el-card>
    </div>
</template>
<script>
import HtmlCapture from '@/components/html-capture'
export default {
    name: 'HtmlCaptureExample'
    components: {
        HtmlCapture
    },
    data () {
        return {
            elData: [
                {url: '/static/html/test1.html'},
                {url: '/static/html/test2.html'},                {url: '/static/html/test3.html'}
            ]
        }
    }
}

大部分网站是不允许跨域的,因此测试还是使用自己本地页面

效果如下图


官网也提到不是所有的CSS都支持,不过一般对于模板展示类的需求还是可以满足。