html2canvas保存图片,可加文字/图片/二维码

vue-cli项目中,运用element

  1. 图片上可以加文字/图片,加这些的可以使用鼠标拖拽改变大小或位置
  2. 支持保存图片
  3. 支持生成二维码
  4. 支持手机查看

安装三个插件:

安装生成二维码

npm install qrcodejs2 --save-dev

安装拖拽缩放组件

 npm install vue-drag-resize --save-dev

 安装html2canvas

npm install html2canvas --save-dev

 html2canvas库的工作原理并不是真正的“截图”,而是读取网页上的目标DOM节点的信息来绘制canvas,所以它并不支持所有的css属性

代码:

<template>
    <div class="generate_picture">
        <el-row class="inner">
            <el-main>
                <div class="generate_imgBox">
                    <div class="generate_imgInner">
                        <div id="dragContainer">
                            <img :src="imgUrl">

                            <VueDragResize :aspectRatio="true" :parentLimitation="false" :w="142" :h="142" :minw="100" :minh="100" :x="458" :y="100" v-on:resizing="resize" v-show="showQrCode">
                                <div id="qrCode" class="qrcode" ref="qrCodeDiv" style="width: 102px;height: 102px;" :style="{ background: qrCodeBgColor }"></div>
                            </VueDragResize>

                            <VueDragResize :aspectRatio="true" :parentLimitation="false" :w="142" :h="142" :minw="100" :minh="100" :x="150" :y="100" v-show="showContactImg">
                                <img class="contact_img" :src="contactImg">
                            </VueDragResize>

                            <VueDragResize :aspectRatio="false" :isResizable="true" :parentLimitation="false" :w="100" :h="50" :minh="50" :x="50" :y="50" v-on:resizing="resizePone" v-show="showword">
                                <pre :style="{ color: wordColor, background: bgColor, fontSize: fontsize + 'px' }">{{ word }}</pre>
                            </VueDragResize>
                        </div>
                    </div>
                    <p>使用鼠标拖拽可改变二维码大小或位置</p>
                </div>

                <div class="generate_from">
                    <div class="generate_from_box">
                        <el-row class="generate_from_tab">
                            <ul>
                                <li v-for="(item,index) in tabs" :class="{ bor_active: tabNum == index}" @click="tabNum = index">{{ item }}</li>
                            </ul>
                        </el-row>

                        <el-row class="generate_from_bot" v-show="tabNum == 0">
                            <p>二维码颜色</p>
                            <el-color-picker v-model="qrCodeColor" @active-change="qrCodeColorActive"></el-color-picker>
                            <p>二维码背景</p>
                            <el-color-picker v-model="qrCodeBgColor" @active-change="qrCodeBgColorActive"></el-color-picker>
                            <p>二维码颜色</p>
                            <el-input
                                type="textarea"
                                :rows="2"
                                placeholder="请输入内容"
                                v-model="qrCodeLink"
                                @input="qrCodeLinkInput">
                            </el-input>
                            <el-checkbox v-model="showQrCode">二维码预览</el-checkbox>
                        </el-row>
                        
                        <el-row class="generate_from_bot" v-show="tabNum == 1">
                            <p>图片</p>
                            <el-upload
                                class="upload-demo"
                                :action="upUrl"
                                :data="qn"
                                :on-success="handleSuccess"
                                :on-remove="handleRemove">
                                <el-button size="small" class="btn_bor_primary" round plain>上传图片</el-button>
                            </el-upload>
                        </el-row>

                        <el-row class="generate_from_bot generate_from_three" v-show="tabNum == 2">
                            <p>文字1</p>
                            <textarea 
                                placeholder="请输入内容" 
                                cols="30" 
                                rows="10"
                                v-model="word"
                                :style="{ color: wordColor, background: bgColor }"></textarea>
                            <p>颜色</p>
                            <el-color-picker v-model="wordColor" @active-change="wordColorActive1"></el-color-picker>
                            <p>背景</p>
                            <el-color-picker v-model="bgColor" @active-change="bgColorActive1"></el-color-picker>
                            <el-checkbox v-model="showword" class="fix" style="margin-bottom: 24px;">文字预览</el-checkbox>
                        </el-row>
                    </div>

                    <div class="generate_from_btn">
                        <el-button class="btn_bor_primary" round plain @click="saveLocalClick">保存本地</el-button>
                        <el-popover
                            placement="top"
                            width="200"
                            trigger="click">
                            <div class="popover-content" style="height: 170px">
                                <div id="qrCode" class="qrcode" ref="imgQrCodeDiv" style="width: 170px;height: 170px;margin: 0 auto"></div>
                            </div>
                            <el-button slot="reference" class="btn_bor_primary" round plain @click="mobileViewClick">手机查看</el-button>
                        </el-popover>
                        <el-button class="btn_bor_primary" round plain @click="previewClick">预览</el-button>
                    </div>
                </div>
            </el-main>
        </el-row>
    </div>
</template>

<script>
    import QRCode from 'qrcodejs2';
    import VueDragResize from "vue-drag-resize";
    import html2canvas from "html2canvas";
    export default {
        data() {
            return {
                imgUrl: require("../../assets/img/d8f9d72a6059252d715289453f9b033b5bb5b92e.jpg"),
                tabs: ['二维码', '图片', '文字信息'],
                tabNum: 0,
                // 二维码
                qrCodeColor: "#000",
                qrCodeBgColor: "#fff",
                qrCodeLink: "https://www.xxx.com/",
                showQrCode: false,
                canvasWidth: 92,
                canvasHeight: 92,
                // 上传初始化
                qn:{
                    token: ""
                },
                upUrl: "",
                // 上传成功后展示IMG
                showContactImg: false,
                contactImg: "",
                // 文字
                word:"",
                wordColor: "red",
                bgColor: "",
                showword: false,
                fontsize: 16,
            }
        },
        methods: {
            // 上传初始化获取上传接口地址和token
            UpImgData () {
                // ...
            },
            // 初始化
            bindQRCode: function () {
                new QRCode(this.$refs.qrCodeDiv, {
                    text: this.qrCodeLink,
                    width: 92,
                    height: 92,
                    colorDark: this.qrCodeColor, //二维码颜色
                    colorLight: "#ff000000", //二维码背景色
                    correctLevel: QRCode.CorrectLevel.L//容错率,L/M/H
                })
            },
            // 缩放时事件
            resize(newRect) {
                document.getElementsByClassName('qrcode')[0].style.width = (newRect.width - 40) + "px";
                document.getElementsByClassName('qrcode')[0].style.height = (newRect.height - 40) + "px";
                document.getElementsByTagName('canvas')[0].style.width = (newRect.width - 50) + "px";
                document.getElementsByTagName('canvas')[0].style.height = (newRect.height - 50) + "px";
                this.canvasWidth = (newRect.width - 50);
                this.canvasHeight = (newRect.height - 50);
            },
            resizePone(newRect) {
                if(newRect.width < 100){
                    this.fontsize = 16
                }else{
                    var v = (newRect.width - 100) / 5
                    this.fontsize = 16 + v
                }
            },
            // 二维码链接输入事件
            qrCodeLinkInput () {
                this.$refs.qrCodeDiv.innerHTML = '';
                new QRCode(this.$refs.qrCodeDiv, {
                    text: this.qrCodeLink,
                    width: this.canvasWidth,
                    height: this.canvasHeight,
                    colorDark: this.qrCodeColor, //二维码颜色
                    colorLight: "#ff000000", //二维码背景色
                    correctLevel: QRCode.CorrectLevel.L//容错率,L/M/H
                })
            },
            // 二维码颜色面板中当前显示的颜色发生改变时触发
            qrCodeColorActive (val) {
                this.$refs.qrCodeDiv.innerHTML = '';
                new QRCode(this.$refs.qrCodeDiv, {
                    text: this.qrCodeLink,
                    width: this.canvasWidth,
                    height: this.canvasHeight,
                    colorDark: val, //二维码颜色
                    colorLight: "#ff000000", //二维码背景色
                    correctLevel: QRCode.CorrectLevel.L//容错率,L/M/H
                })
            },
            // 二维码背景面板中当前显示的颜色发生改变时触发
            qrCodeBgColorActive (val) {
                this.qrCodeBgColor = val
            },
            // 文字颜色面板中当前显示的颜色发生改变时触发
            wordColorActive1 (val) {
                this.wordColor = val
            },
            bgColorActive1 (val) {
                this.bgColor = val
            },
            // 图片上传成功
            handleSuccess(res, file) {
                this.showContactImg = true;
                this.contactImg = res.file_path
            },
            // 删除图片
            handleRemove() {
                this.showUploadBtn = true;
                this.contactImg = ""
            },
            // 抽出公共图片
            opts () {
                var dragContainer = document.getElementById("dragContainer");
                let opts = {
                    useCORS: true,
                    height: dragContainer.offsetHeight, // 解决当页面滚动之后生成图片出现白边问题
                    width: dragContainer.offsetWidth,
                    scrollX: -8,
                    dpi: 300, // 处理模糊问题
                    scale: 1
                };
                return opts
            },
            // 保存图片
            saveLocalClick(){
                var _this = this;
                var dragContainer = document.getElementById("dragContainer");
                html2canvas(dragContainer,_this.opts).then((canvas) => {
                    var url = canvas.toDataURL('image/png');    
                    var a = document.createElement("a");
                    a.href = url;
                    a.download = "素材";
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                });
            },
            // 手机查看
            mobileViewClick () {
                var _this = this;
                this.$refs.imgQrCodeDiv.innerHTML = '';
                var dragContainer = document.getElementById("dragContainer");
                html2canvas(dragContainer,_this.opts).then((canvas) => {
                    canvas.toBlob(function (blobObj) {
                        var formData = new FormData();
                        // _this.qn.token和_this.upUrl是上传初始化接口返回的
                        formData.append("token", _this.qn.token);
                        formData.append("file", blobObj);
                        // 把图片上加文字/二维码生成的新图片传给上传提交的接口,然后获取接口返回的新图片链接,把这个链接生成二维码,才能给手机扫描查看
                        _this.$http.post(_this.upUrl, formData).then(res => {
                            new QRCode(_this.$refs.imgQrCodeDiv, {
                                text: res.data.file_path,
                                width: 170,
                                height: 170,
                                colorDark: "#000", //二维码颜色
                                colorLight: "#fff", //二维码背景色
                                correctLevel: QRCode.CorrectLevel.L//容错率,L/M/H
                            })
                        }).catch(err => {
                        })
                    })
                });
            },
            // 预览
            previewClick() {
                var _this = this;
                var dragContainer = document.getElementById("dragContainer");
                html2canvas(dragContainer,_this.opts).then(function(canvas) {
                    canvas.toBlob(function (blobObj) {
                        console.log(blobObj)
                        window.open(URL.createObjectURL(blobObj))
                    })
                });
            },
        },  
        mounted () {
            this.$nextTick(function () {
                this.bindQRCode();
            });
        },
        components:{
            VueDragResize
        }
    }
</script>

<style scoped>
    .generate_picture .inner{
        width: 1200px;
        margin: 25px auto;
    }
    .generate_picture .el-main {
        width: 100%;
        min-height: 980px;
        background-color: #fff;
        border-radius: 10px;
        float: right;
    }

    .generate_imgBox{
        border-radius: 4px;
        -webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .04);
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .04);
        border: solid 1px #eeeeee;
        height: 600px;
        width: 794px;
        -webkit-box-flex: 1;
        -webkit-flex: 1;
        -ms-flex: 1;
        flex: 1;
        padding: 9px;
        /* text-align: center; */
        position: relative;
        float: left;
    }
    .generate_imgInner{
        position: absolute;
        border-radius: 4px;
        left: 20px;
        top: 20px;
        border: solid 1px #eeeeee;
        height: 560px;
        width: 770px;
        overflow: auto;
    }
    .generate_imgInner::-webkit-scrollbar{
        width: 8px;
        height: 8px;
    }
    .generate_imgInner::-webkit-scrollbar{
        width: 5px !important;
        margin-right: 8px;
    }
    .generate_imgInner::-webkit-scrollbar-thumb,
    .generate_imgInner::-webkit-scrollbar-thumb:horizontal{
        border-radius: 2.5px;
        background: #a5a9b3;
    }
    .generate_imgInner::-webkit-scrollbar-track,
    .generate_imgInner::-webkit-scrollbar-track-piece{
        border-radius: 2.5px;
    }
    .generate_imgInner::-webkit-scrollbar-track,
    .generate_imgInner::-webkit-scrollbar-track-piece{
        border-radius: 2.5px;
    }

    #dragContainer{
        width: auto;
        display: inline-grid;
        position: relative;
    }
    #dragContainer .qrcode{
        padding: 10px;
        margin: 10px;
        background-color: #fff;
        display: -webkit-box;
        display: -webkit-flex;
        display: -ms-flexbox;
        display: flex;
        -webkit-box-pack: center;
        -webkit-justify-content: center;
        -ms-flex-pack: center;
        justify-content: center;
        -webkit-box-align: center;
        -webkit-align-items: center;
        -ms-flex-align: center;
        align-items: center;
        position: relative;
    }
    #dragContainer img.contact_img{
        width: 100%;
    }
    #dragContainer pre{
        padding: 0 6px;
        font-size: 16px;
        text-align: center;
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: 100%;
        word-break: break-all;
        white-space: pre-wrap;
    }

    .generate_from{
        width: 330px;
        height: auto;
        overflow: hidden;
        float: right;
    }
    .generate_from_box{
        border-radius: 4px;
        border: solid 1px #eeeeee;
        min-height: 342px;
        margin: 0;
        height: auto;
        padding: 0;
        -webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .04);
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .04);
    }

    .generate_from_tab{
        margin: 0 0 16px;
    }
    .generate_from_tab ul li{
        width: 33.3%;
        height: 42px;
        float: left;
        line-height: 42px;
        text-align: center;
        font-size: 14px;
        border-bottom: 1px #eee solid;
        cursor: pointer;
    }
    .generate_from_tab ul li.bor_active{
        border-bottom-width: 2px;
    }

    .generate_from_bot{
        padding: 0px 20px 10px 20px;
    }
    .generate_from_bot p{
        color: #414755;
        opacity: 0.6;
        font-size: 14px;
        padding-bottom: 8px;
    }
    .generate_from_bot .el-color-picker{
        margin-bottom: 10px;
    }
    .generate_from_bot .el-color-picker__trigger{
        width: 290px;
        border: 0;
        padding: 0;
        border: 1px #eee solid;
        border-radius: 5px;
    }
    .generate_from_bot .el-color-picker__icon{
        display: none;
    }
    .generate_from_bot .el-color-picker__color{
        border: 0;
        border-radius: 5px;
    }
    .generate_from_bot textarea{
        margin-bottom: 10px;
        width: 100%;
        min-height: 50px;;
        height: 100px;
        padding: 5px 15px;
        display: block;
        resize: vertical;
        box-sizing: border-box;
        font-size: inherit;
        color: #606266;
        background-color: #FFF;
        border: 1px solid #DCDFE6;
        border-radius: 4px;
        transition: border-color .2s cubic-bezier(.645,.045,.355,1);
        outline:none;
    }
    .generate_from_bot .el-checkbox{
        float: right;
        margin-right: 0;
    }

    .generate_from_three{
        max-height: 600px;
        overflow: auto;
    }
    .generate_from_three::-webkit-scrollbar {
        width: 5px !important;
        margin-right: 8px;
    }
    .generate_from_three::-webkit-scrollbar-thumb, 
    .generate_from_three::-webkit-scrollbar-thumb:horizontal {
        border-radius: 2.5px;
        background: #a5a9b3;
    }
    .generate_from_three::-webkit-scrollbar-track, 
    .generate_from_three::-webkit-scrollbar-track-piece {
        border-radius: 2.5px;
    }
    .generate_from_three::-webkit-scrollbar-track, 
    .generate_from_three::-webkit-scrollbar-track-piece {
        border-radius: 2.5px;
    }

    .generate_from_bot .divider-dashed{
        background: none;
        border: dashed #e8e8e8;
        border-width: 1px 0 0;
        display: block;
        clear: both;
        width: 100%;
        min-width: 100%;
        height: 1px;
        margin: 24px 0;
    }


    .generate_from_btn{
        margin-top: 20px;
        display: -webkit-box;
        display: -webkit-flex;
        display: -ms-flexbox;
        display: flex;
        -webkit-box-pack: center;
        -webkit-justify-content: center;
        -ms-flex-pack: center;
        justify-content: center;
    }
    .generate_from_btn .el-button{
        width: 33%;
        height: 28px;
        line-height: 0.3;
    }
    .generate_from_btn span{
        margin: 0 6px;
    }
    .generate_from_btn span .el-button{
        width: 100%;
    }


    .generate_imgBox p{
        color: rgb(65, 71, 85);
        opacity: 0.6;
        position: absolute;
        bottom: -34px;
    }
</style>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值