html2canvas简单示例

公司要求开发一个组件功能,希望将html元素变成图片;话不多说,直接上代码;
代码中的文件链接:
vue.jshtml2canvas.js,element-ui.css,element-ui.js
(上面的文件链接是放在我自己的服务器上。如果打开慢,请去官网下载。请不要使用我的超链接放在代码中,因为带宽太差了。请下载下来使用)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./插件/vue.js"></script>
    <script src="./插件/html2canvas.js"></script>
    <link rel="stylesheet" href="./插件/element-ui.css">
    <script src="./插件/element-ui.js"></script>
</head>

<body>
    <!-- 创建一个根元素 -->
    <div class="home" id="home" style="width: 620px;margin:auto;">
        <el-form class="bg-control" label-position="right" label-width="110px" :rules="rules" :model="form">
            <!-- <el-form-item label=" 媒体名称:" prop="mediaName">
                <el-input size="small" placeholder="请输入媒体名称" v-model="form.mediaName" clearable></el-input>
            </el-form-item> -->
            <el-form-item label="适配分辨率:" prop="width_height">
                <el-input size="small" placeholder="输入格式例如:1920*1080" v-model="form.width_height" clearable @change="changeWidth_height" @focus="savedOldData"></el-input>
            </el-form-item>
            <el-form-item label="背景版颜色:" prop="color">
                <el-color-picker size="small" v-model="form.bgColor" show-alpha :predefine="predefineColors" @change="changeBgColor">
                </el-color-picker>
            </el-form-item>
            <el-form-item label="媒体的内容:" class="media-content">
                <div class="set">
                    <span>字体:</span>
                    <el-select size="small" v-model="form.fontFamily" @change="changeFont('fontFamily')">
                        <el-option value="SimSun" label="宋体"></el-option>
                        <el-option value="SimHei" label="黑体"></el-option>
                        <el-option value="Microsoft Yahei" label="微软雅黑"></el-option>
                        <el-option value="Microsoft JhengHei" label="微软正黑体"></el-option>
                        <el-option value="KaiTi" label="楷体"></el-option>
                        <el-option value="NSimSun" label="新宋体"></el-option>
                        <el-option value="FangSong" label="仿宋"></el-option>
                        <el-option value="cursive" label="手写草体"></el-option>
                    </el-select>
                </div>
                <div class="set">
                    <span>对齐方式:</span>
                    <el-select size="small" v-model="form.textAlign" @change="changeFont('textAlign')">
                        <el-option value="left" label="左对齐"></el-option>
                        <el-option value="right" label="右对齐"></el-option>
                        <el-option value="center" label="居中"></el-option>
                    </el-select>
                </div>
                <div class="set">
                    <span>颜色:</span>
                    <el-color-picker size="small" v-model="form.color" show-alpha :predefine="predefineColors" @change="changeFont('color')">
                    </el-color-picker>
                </div>
                <div class="set">
                    <span>字行高:</span>
                    <el-input-number size="small" v-model="form.lineHeight" :min="1" :step="0.5" @change="changeFont('lineHeight','em')"></el-nput-number>
                </div>
                <div class="set">
                    <span>字号:</span>
                    <el-input-number size="small" v-model="form.fontSize" :step="1" :min="10" @change="changeFont('fontSize','px')"></el-nput-number>
                </div>
                <div class="set">
                    <span>字间距:</span>
                    <el-input-number size="small" v-model="form.letterSpacing" :min="0" :step="0.5" @change="changeFont('letterSpacing','px')"></el-nput-number>
                </div>
                <div class="set">
                    <span>加粗:</span>
                    <el-input-number size="small" v-model="form.fontWeight" :step="100" :min="100" :max="900" @change="changeFont('fontWeight')"></el-nput-number>
                </div>
            </el-form-item>
            <el-button type="primary" size="small" @click="addTxt" :disabled="!form.width_height">添加文字</el-button>
            <el-button type="primary" size="small" @click="saved" :disabled="!form.width_height">生成canvas</el-button>
        </el-form>
        <div class="box-bg-container" :style="{'--pointColor':box.pointColor}">
            <div class="bg-plate-bottom" v-if="box.show" :style="box.bgStyle"></div>
            <div class="bg-plate" ref="bgPlate" v-if="box.show" :style="box.bgStyle" @mouseup="mouseleaveOrup" @mousemove="mousemove" @mouseleave="mouseleaveOrup" @wheel="changeSize" @click.stop="cancelDblclick">
                <div class="mask" @click.stop="cancelDblclick" v-if="txtStatus.focus" name="遮罩层"></div>
                <div class="suspension" :style="auxiliary.suspension.style" v-if="auxiliary.suspension.show">
                    <div>宽度:{{auxiliary.suspension.width}}px</div>
                    <div>高度:{{auxiliary.suspension.height}}px</div>
                    <div>旋转:{{auxiliary.suspension.rotate}}</div>
                </div>
                <div class="horizontal" name="竖线" v-if="auxiliary.horizontal && txtStatus.move"></div>
                <div class="vertical" name="横线" v-if="auxiliary.vertical && txtStatus.move"></div>
                <div class="txtBox" v-for="(item, index) in box.txtBox" :style="item.boxStyle" @dblclick="selectText(index)" @mousedown="mousedown(index, $event)" @click.stop>
                    <div class="border" v-if="(txtStatus.move || txtStatus.focus) && index == txtStatus.index" @mousedown="changeWidth_down">
                        <div class="btn delete el-icon-delete" title="按下键盘delete" @click.stop="deleteTxt(index)"></div>
                        <div class="btn left-top"></div>
                        <div class="btn right-top"></div>
                        <div class="btn right"></div>
                        <div class="btn right-bottom"></div>
                        <div class="btn left-bottom"></div>
                        <div class="btn left"></div>
                        <div class="btn rotate el-icon-refresh"></div>
                    </div>
                    <div class="txt" :class="[`txt_${index}`]" ref="txtref" ondragstart="return false" :contenteditable="txtStatus.focus && index == txtStatus.index" :style="item.txtStyle">
                        {{ item.txt }}
                    </div>
                </div>

            </div>
        </div>
    </div>

</body>
<script>
    // 将vue挂载到id为home的根元素上
    new Vue({
        el: "#home",
        data() {
            return {
                predefineColors: [
                    '#ff4500',
                    '#ff8c00',
                    '#ffd700',
                    '#90ee90',
                    '#00ced1',
                    '#1e90ff',
                    '#c71585',
                    'rgba(255, 69, 0, 0.68)',
                    'rgb(255, 120, 0)',
                    'hsv(51, 100, 98)',
                    'hsva(120, 40, 94, 0.5)',
                    'hsl(181, 100%, 37%)',
                    'hsla(209, 100%, 56%, 0.73)',
                    '#c7158577'
                ],
                templateTxt: {
                    txt: '双击编辑文字',
                    boxStyle: {
                        width: 'max-content',
                        border: `1px dashed transparent`,
                        left: '10px',
                        top: '10px',
                        transform: 'rotate(0deg)'

                    },
                    txtStyle: {
                        color: 'rgb(255, 255, 255)',
                        fontSize: '66px',
                        pointerEvents: 'auto',
                        fontFamily: 'SimSun',
                        textAlign: 'left',
                        lineHeight: 1,
                        letterSpacing: 0,
                        fontWeight: 500,
                    }
                },
                auxiliary: {
                    horizontal: false,
                    vertical: false,
                    suspension: {
                        width: '', //悬浮框内容中的宽度字段
                        height: '', //悬浮框内容中的高度字段
                        rotate: '', //悬浮框内容中的旋转字段
                        show: false, //悬浮框是否显示
                        move: false, //悬浮框是否移动
                        btnName: null, //被点击的元素className

                        startX: null, //被点击的元素的起点
                        startWidth: null, //元素被按下鼠标拖拽放大缩小时,文字框架的宽
                        fontSize: null, //元素被按下鼠标拖拽放大缩小时,文字的大小
                        startLeft: null, //元素被按下鼠标拖拽放大缩小时,文字框架的left位置
                        startTop: null, //元素被按下鼠标拖拽放大缩小时,文字框架的top位置
                        startRotate: null, //元素被按下鼠标拖拽旋转时,文字框架当时的旋转的角度

                        style: {
                            left: '0',
                            top: '0'
                        }
                    }
                },
                form: {
                    mediaName: '',
                    width_height: '',
                    bgColor: 'rgba(0,0,0,1)',
                    old_width_height: '',
                    fontFamily: null,
                    textAlign: '',
                    color: null,
                    lineHeight: undefined,
                    fontSize: undefined,
                    letterSpacing: undefined,
                    fontWeight: undefined,
                },

                box: {
                    pointColor: '#c1c1c1', //
                    show: false, //背景版的开关
                    bgStyle: {
                        width: '1000px',
                        height: '600px',
                        transform: 'scale(1)',
                        backgroundColor: '',
                    }, //背景版的style
                    txtBox: [], //文字数组
                },

                txtStatus: {
                    focus: false,
                    move: false,
                    index: null,
                    EleStartX: null, //元素的起始点
                    EleStartY: null, //元素的起始点
                    mouseStartX: null,
                    mouseStartY: null
                },
                rules: {
                    mediaName: [{
                        required: true,
                        message: '请输入媒体名称',
                        trigger: 'blur'
                    }, ],
                    width_height: [{
                        required: true,
                        message: '请输入适配分辨率',
                        trigger: 'blur'
                    }, ]
                }
            }
        },
        mounted() {
            window.addEventListener('keydown', (e) => {
                switch (e.key) {
                    case 'Escape':
                        if (this.txtStatus.focus) this.cancelDblclick();
                        break;
                    case 'Delete':
                        if (this.txtStatus.focus) this.deleteTxt(this.txtStatus.index);
                        break;
                    default:
                        break
                }
            })
        },
        beforeDestroy() {

        },
        methods: {
            //保存一下旧的背景版宽高的数据
            savedOldData() {
                this.form.old_width_height = this.form.width_height;
            },
            //修改背景版的颜色
            changeWidth_height() {
                if (this.form.width_height.indexOf('*') == -1) return
                this.createdBox();
                let arrnew = this.form.width_height.split('*');
                let arrold = this.form.old_width_height.split('*');
                for (let i in this.box.txtBox) {
                    let left = parseFloat(this.box.txtBox[i].boxStyle.left);
                    let top = parseFloat(this.box.txtBox[i].boxStyle.top);
                    this.box.txtBox[i].boxStyle.left = (left + (arrnew[0] - arrold[0]) / 2) + 'px';
                    this.box.txtBox[i].boxStyle.top = (top + (arrnew[1] - arrold[1]) / 2) + 'px';
                }
            },
            //新建背景版
            createdBox() {
                this.cancelDblclick();
                if (!this.form.width_height) return
                let arr = this.form.width_height.split('*');
                this.box.bgStyle.width = arr[0] + 'px';
                this.box.bgStyle.height = arr[1] + 'px';
                let father = document.querySelector('.box-bg-container');
                let fatherHeight = father.offsetHeight;
                let fatherWidth = father.offsetWidth;
                this.box.bgStyle.left = (fatherWidth - arr[0]) / 2 + 'px';
                this.box.bgStyle.top = (fatherHeight - arr[1]) / 2 + 'px';
                this.box.bgStyle.backgroundColor = this.form.bgColor;
                this.box.show = true;
            },
            //提交保存
            saved() {
                this.cancelDblclick();
                let ele = this.$refs.bgPlate;
                if (!ele) return;
                let ele_clone = ele.cloneNode(true);
                let boxBig = document.querySelector('.box-bg-container')
                boxBig.appendChild(ele_clone)
                let scale = this.box.bgStyle.transform;
                this.box.bgStyle.transform = 'scale(1)';
                this.box.bgStyle.zIndex = '-1';
                this.$nextTick(() => {
                    html2canvas(ele).then((canvas) => {
                        let newCanvas = document.body.appendChild(canvas)
                        let newImg = newCanvas.toDataURL('image/png');
                        console.log('base64', newImg);
                        console.log('数据类型', JSON.stringify(this.box));

                        // this.box.bgStyle.transform = scale; //还原
                        // delete this.box.bgStyle.zIndex; //还原
                        // boxBig.removeChild(ele_clone); //还原
                        // newCanvas.remove();
                    })
                })
            },
            //删除文字
            deleteTxt(index) {
                this.box.txtBox.splice(index, 1);
                this.txtStatus.index = null;
                this.txtStatus.focus = false;
            },

            //控制中间线的出现和隐藏
            horizontal_vertical(i) {
                let boxEle = this.$refs.txtref[i].parentElement;
                let centerX = parseFloat(this.box.bgStyle.width) / 2 - boxEle.offsetWidth / 2; //背景板中心的x坐标-当前元素的width
                let centerY = parseFloat(this.box.bgStyle.height) / 2 - boxEle.offsetHeight / 2; //背景板中心的y坐标-当前元素的height
                let left = parseFloat(this.box.txtBox[i].boxStyle.left); //获取当前的元素的left坐标
                let top = parseFloat(this.box.txtBox[i].boxStyle.top); //获取当前的元素的top坐标

                if (left < centerX + 2 && left > centerX - 2) this.auxiliary.horizontal = true; //当前的元素的 left 坐标与居中的位置相差± 3的时候,显示,否则不显示
                else this.auxiliary.horizontal = false;

                if (top < centerY + 2 && top > centerY - 2) this.auxiliary.vertical = true; //当前的元素的 top 坐标与居中的位置相差± 3的时候,显示,否则不显示
                else this.auxiliary.vertical = false;
            },
            //按下鼠标:记录各个工作的起始点
            mousedown(index, e) {
                if (e.button != 0) return
                if (this.txtStatus.focus) return
                this.box.txtBox[index].txtStyle.cursor = 'move';
                this.box.txtBox[index].boxStyle.border = `1px dashed ${this.box.pointColor}`;
                this.txtStatus.move = true;
                this.txtStatus.index = index;
                let parentEle = e.target.parentNode;
                this.txtStatus.EleStartX = parseFloat(parentEle.style.left);
                this.txtStatus.EleStartY = parseFloat(parentEle.style.top);
                this.txtStatus.mouseStartX = e.pageX; //记录鼠标点击的起始点
                this.txtStatus.mouseStartY = e.pageY; //记录鼠标点击的起始点
                this.box.txtBox.splice();
            },
            // 按下鼠标:记录各个工作的起始点
            changeWidth_down(e) {
                if (e.button != 0) return
                if (!this.txtStatus.focus) return
                let classList = e.target.classList;
                if (classList[1] == 'delete') return
                this.auxiliary.suspension.btnName = classList[1];
                this.auxiliary.suspension.startX = e.pageX;
                this.auxiliary.suspension.startY = e.pageY;
                let i = this.txtStatus.index;
                this.auxiliary.suspension.move = true;
                let ele_txt = this.$refs.txtref[i].getBoundingClientRect();
                if (classList[1] == 'left') {
                    this.auxiliary.suspension.startwidth = parseFloat(ele_txt.width)
                    this.auxiliary.suspension.startLeft = parseFloat(this.box.txtBox[i].boxStyle.left);
                } else if (classList[1] == 'right') {
                    this.auxiliary.suspension.startwidth = parseFloat(ele_txt.width);
                } else if (classList[1] == 'left-top' || classList[1] == 'right-top' || classList[1] == 'left-bottom') {
                    this.auxiliary.suspension.fontSize = parseFloat(this.box.txtBox[i].txtStyle.fontSize);
                    this.auxiliary.suspension.startLeft = parseFloat(this.box.txtBox[i].boxStyle.left);
                    this.auxiliary.suspension.startTop = parseFloat(this.box.txtBox[i].boxStyle.top);
                } else if (classList[1] == 'right-bottom') {
                    this.auxiliary.suspension.fontSize = parseFloat(this.box.txtBox[i].txtStyle.fontSize);
                    this.auxiliary.suspension.startLeft = parseFloat(this.box.txtBox[i].boxStyle.left);
                } else if (classList[1] == 'rotate') {
                    let ele_w = parseFloat(this.$refs.txtref[i].offsetWidth);
                    let ele_h = parseFloat(this.$refs.txtref[i].offsetHeight);
                    let ele_l = parseFloat(this.box.txtBox[i].boxStyle.left);
                    let ele_t = parseFloat(this.box.txtBox[i].boxStyle.top);
                    let orginX = ele_l + ele_w / 2;
                    let orginY = ele_t + ele_h / 2;
                    this.auxiliary.suspension.startRotate = [orginX, orginY]
                }
                this.showSuspension(e)
            },
            //拖拽鼠标:计算移动的距离
            mousemove(e) {
                let scale = parseFloat(this.box.bgStyle.transform.replace('scale(', '').replace(')', ''));
                if (this.txtStatus.move && !this.txtStatus.focus) {
                    let moveX = this.txtStatus.mouseStartX - e.pageX; //鼠标移动的距离
                    let moveY = this.txtStatus.mouseStartY - e.pageY; //鼠标移动的距离
                    let i = this.txtStatus.index;
                    this.box.txtBox[i].boxStyle.left = this.txtStatus.EleStartX - moveX / scale + 'px'
                    this.box.txtBox[i].boxStyle.top = this.txtStatus.EleStartY - moveY / scale + 'px'
                    this.horizontal_vertical(i);
                } //当处于移动的状态的时候,执行此功能会一直修改元素的位置
                else if (this.auxiliary.suspension.move && this.txtStatus.focus) {
                    let moveX = this.auxiliary.suspension.startX - e.pageX; //鼠标移动的距离
                    let moveY = this.auxiliary.suspension.startY - e.pageY; //鼠标移动的距离
                    let i = this.txtStatus.index;
                    let btnName = this.auxiliary.suspension.btnName;
                    if (btnName == 'left') {
                        moveX = moveX / scale;
                        this.box.txtBox[i].boxStyle.width = (this.auxiliary.suspension.startwidth + moveX) / scale + 'px';
                        this.box.txtBox[i].boxStyle.left = (this.auxiliary.suspension.startLeft - moveX) + 'px'
                    } else if (btnName == 'right') {
                        moveX = moveX / scale;
                        this.box.txtBox[i].boxStyle.width = (this.auxiliary.suspension.startwidth - moveX * scale) / scale + 'px';
                    } else if (btnName == 'left-top') {
                        moveX = moveX / scale;
                        this.box.txtBox[i].txtStyle.fontSize = this.auxiliary.suspension.fontSize + moveX + 'px';
                        this.box.txtBox[i].boxStyle.left = this.auxiliary.suspension.startLeft - moveX + 'px';
                        this.box.txtBox[i].boxStyle.top = this.auxiliary.suspension.startTop - moveY + 'px';
                        this.form.fontSize = parseFloat(this.box.txtBox[i].txtStyle.fontSize);
                    } else if (btnName == 'left-bottom') {
                        this.box.txtBox[i].txtStyle.fontSize = this.auxiliary.suspension.fontSize + moveX + 'px';
                        this.box.txtBox[i].boxStyle.left = this.auxiliary.suspension.startLeft - moveX + 'px';
                        this.box.txtBox[i].boxStyle.top = this.auxiliary.suspension.startTop + moveY + 'px';
                        this.form.fontSize = parseFloat(this.box.txtBox[i].txtStyle.fontSize);
                    } else if (btnName == 'right-top') {
                        let txt = this.box.txtBox[i].txt.length;
                        this.box.txtBox[i].txtStyle.fontSize = this.auxiliary.suspension.fontSize - moveX + 'px';
                        this.box.txtBox[i].boxStyle.left = this.auxiliary.suspension.startLeft + moveX * (txt - 1) + 'px';
                        this.box.txtBox[i].boxStyle.top = this.auxiliary.suspension.startTop + moveY + 'px';
                        this.form.fontSize = parseFloat(this.box.txtBox[i].txtStyle.fontSize);
                    } else if (btnName == 'right-bottom') {
                        let txt = this.box.txtBox[i].txt.length;
                        this.box.txtBox[i].txtStyle.fontSize = this.auxiliary.suspension.fontSize - moveX + 'px';
                        this.box.txtBox[i].boxStyle.left = this.auxiliary.suspension.startLeft + moveX * (txt - 1) + 'px';
                        this.form.fontSize = parseFloat(this.box.txtBox[i].txtStyle.fontSize);
                    } else if (btnName == 'rotate') {
                        if (!this.auxiliary.suspension.startRotate) return
                        let orginX = this.auxiliary.suspension.startRotate[0]; //围绕选择的中心点
                        let orginY = this.auxiliary.suspension.startRotate[1]; //围绕选择的中心点
                        let boxH = parseFloat(this.box.bgStyle.height);
                        let ele = document.querySelector('.bg-plate').getBoundingClientRect();
                        let x = (e.pageX - ele.left) / scale;
                        let y = (e.pageY - ele.top) / scale;
                        let rotate = this.getAngle([orginX - orginX, boxH - orginY], [x - orginX, y - orginY])
                        this.box.txtBox[i].boxStyle.transform = `rotate(${rotate.toFixed(2)}deg)`
                    }
                    if (parseFloat(this.box.txtBox[i].txtStyle.fontSize) * scale < 10) this.auxiliary.suspension.move = false
                    this.showSuspension(e)
                } //当处于修改宽高的状态的时候,执行此功能会一直修改元素的宽高
            },

            //销毁移动;清空各个变量的状态
            mouseleaveOrup(e) {
                if (e.button != 0) return
                if (!this.txtStatus.focus && this.txtStatus.move) {
                    let i = this.txtStatus.index;
                    this.box.txtBox[i].txtStyle.cursor = 'default';
                    this.box.txtBox[i].boxStyle.border = "1px dashed transparent";
                    this.txtStatus.mouseStartX = null;
                    this.txtStatus.mouseStartY = null;
                    this.txtStatus.EleStartX = null;
                    this.txtStatus.EleStartY = null;
                    this.txtStatus.move = false;
                    this.txtStatus.index = 0;
                    this.box.txtBox.splice();
                } //当处于移动的状态的时候,执行此功能会关闭移动的状态
                else if (this.txtStatus.focus && this.auxiliary.suspension.move) {
                    this.auxiliary.suspension.show = false;
                    this.auxiliary.suspension.move = false;
                    this.auxiliary.suspension.btnName = null;
                    this.auxiliary.suspension.startX = null;
                    this.auxiliary.suspension.startWidth = null;
                    this.auxiliary.suspension.fontSize = null;
                    this.cancelDblclick()
                } //当处于修改宽的状态的时候,执行此功能会关闭修改宽高的状态
            },
            //计算旋转角度
            getAngle([x1, y1], [x2, y2]) {
                const dot = x1 * x2 + y1 * y2
                const det = x1 * y2 - y1 * x2
                const angle = Math.atan2(det, dot) / Math.PI * 180
                return (angle + 360) % 360
            },
            //双击文字
            selectText(index) {
                this.txtStatus.focus = true;
                this.txtStatus.index = index;
                this.box.txtBox[index].txtStyle.cursor = 'text';
                this.box.txtBox[index].boxStyle.border = `1px dashed ${this.box.pointColor}`;
                this.box.txtBox.splice();
                this.$nextTick(() => {
                    let ele = this.$refs.txtref[index];
                    if (document.selection) {
                        let range = document.body.createTextRange()
                        range.moveToElementText(ele);
                        range.select();
                    } else if (window.getSelection) {
                        let range = document.createRange();
                        range.selectNodeContents(ele)
                        window.getSelection().removeAllRanges()
                        window.getSelection().addRange(range)
                    }
                })
                let txt = this.box.txtBox[index].txtStyle;
                this.form.fontFamily = txt.fontFamily;
                this.form.textAlign = txt.textAlign;
                this.form.color = txt.color;
                this.form.lineHeight = parseFloat(txt.lineHeight);
                this.form.fontSize = parseInt(txt.fontSize);
                this.form.letterSpacing = parseFloat(txt.letterSpacing);
                this.form.fontWeight = parseInt(txt.fontWeight);
            },
            //取消双击效果
            cancelDblclick() {
                let i = this.txtStatus.index;
                if (i === null) return
                if (!this.txtStatus.focus) return
                    // this.box.txtBox[i].txtStyle.backgroundColor = '';
                this.box.txtBox[i].txtStyle.cursor = 'default';
                this.box.txtBox[i].boxStyle.border = "1px dashed transparent";


                this.changeTxt(i)


                this.txtStatus.index = null;
                this.txtStatus.focus = false;
                this.box.txtBox.splice();
                this.form.fontFamily = null;
                this.form.textAlign = null;
                this.form.color = null;
                this.form.lineHeight = undefined;
                this.form.fontSize = undefined;
                this.form.letterSpacing = undefined;
                this.form.fontWeight = undefined;
                this.auxiliary.suspension.show = false
            },
            //添加文字
            addTxt() {
                this.cancelDblclick()
                if (!this.box.show) return
                let txt = JSON.parse(JSON.stringify(this.templateTxt));
                if (!this.box.show) return
                    //当一个字的大小为66,那么这个字框的宽度就是字数*66,高度就是66;这个地方
                let fontS = parseInt(txt.txtStyle.fontSize);
                let txtNum = txt.txt.length;
                txt.boxStyle.left = parseFloat(this.box.bgStyle.width) / 2 - (fontS * txtNum / 2) + 'px';
                txt.boxStyle.top = parseFloat(this.box.bgStyle.height) / 2 - (fontS / 2) + 'px';
                // txt.boxStyle.backgroundColor = this.form.bgColor;
                this.auxiliary.horizontal = true;
                this.auxiliary.vertical = true;
                this.box.txtBox.push(txt);
                let i = this.box.txtBox.length - 1;
                this.selectText(i);
            },

            //小视窗的位置和内部的信息
            showSuspension(e) {
                let i = this.txtStatus.index;
                this.auxiliary.suspension.show = true;
                this.auxiliary.suspension.style.left = e.pageX + 10 + 'px';
                this.auxiliary.suspension.style.top = e.pageY + 10 + 'px';
                let ele_txt = this.$refs.txtref[i];
                this.auxiliary.suspension.width = parseInt(ele_txt.offsetWidth);
                this.auxiliary.suspension.height = parseInt(ele_txt.offsetHeight);
                let rotate = this.box.txtBox[i].boxStyle.transform;
                this.auxiliary.suspension.rotate = rotate.replace('rotate(', '').replace('deg)', '');
            },
            //通过滚轮修改背景的大小
            changeSize(e) {
                e.preventDefault()
                if (this.txtStatus.focus) return;
                if (this.txtStatus.move) return;
                let changeSize; //这可以看做百分比
                if (e.deltaY > 0) changeSize = -0.02;
                else if (e.deltaY < 0) changeSize = 0.02;
                let scale = parseFloat(this.box.bgStyle.transform.replace('scale(', '').replace(')', '')) + changeSize;
                if (scale < 0.05) return
                this.box.bgStyle.transform = `scale(${scale})`

            },
            //修改选中字体的方法
            changeFont(attribute, pixel = '') {
                let i = this.txtStatus.index;
                if (i == null) return
                this.box.txtBox[i].txtStyle[attribute] = this.form[attribute] + pixel;
            },
            //改变背景版的颜色
            changeBgColor() {
                this.box.bgStyle.backgroundColor = this.form.bgColor;
                this.box.txtBox.splice()
            },
            changeTxt(index) {
                this.box.txtBox[index].txt = this.$refs.txtref[index].innerText;
                this.box.txtBox.splice()
            }
        }
    });
</script>
<style lang="scss">
    .bg-control {
        .media-content {
            background-color: #f4f6fa;
            .el-form-item__content {
                display: flex;
                flex-wrap: wrap;
                box-sizing: border-box;
                .set {
                    width: 50%;
                    box-sizing: border-box;
                    display: flex;
                    align-items: center;
                    margin-bottom: 5px;
                    >span {
                        width: 60px;
                        text-align: right;
                        padding-right: 10px;
                    }
                    .el-color-picker {
                        width: 150px;
                        border: 1px solid #e6e6e6;
                        .el-color-picker__trigger {
                            border: none;
                        }
                    }
                    .el-input-number {
                        width: 150px;
                    }
                    .el-select {
                        width: 150px;
                    }
                }
            }
        }
    }
    
    .box-bg-container {
        background-color: #f5f5f5;
        margin-top: 10px;
        border: 1px dashed #616161;
        height: 510px;
        box-sizing: border-box;
        overflow: hidden;
        position: relative;
        .mask {
            width: 100%;
            height: 100%;
            position: absolute;
            background-color: rgba(0, 0, 0, 0);
            left: 0;
            top: 0;
            box-sizing: border-box;
        }
        .bg-plate,
        .bg-plate-bottom {
            overflow: hidden;
            box-shadow: 0 4px 20px var(--stroke--separater);
            box-sizing: border-box;
            transform-origin: center;
            position: absolute;
            .suspension {
                position: fixed;
                color: var(--pointColor);
                font-size: 12px;
                background-color: rgba(0, 0, 0, 0.9);
                padding: 6px 10px;
                z-index: 1;
                border-radius: 10px;
                border: 1px solid #919191;
                user-select: none;
            }
            .horizontal {
                width: 2px;
                height: 100%;
                opacity: 0.5;
                background-color: var(--pointColor);
                position: absolute;
                left: calc(50% + 2px);
                transform: translate(-50%, 0%);
            }
            .vertical {
                width: 100%;
                height: 2px;
                opacity: 0.5;
                background-color: var(--pointColor);
                position: absolute;
                top: calc(50% - 2px);
                transform: translate(0%, -50%);
            }
            .txtBox {
                position: absolute;
                height: auto;
                .border {
                    .btn {
                        user-select: none;
                        width: 8px;
                        height: 8px;
                        background-color: var(--pointColor);
                        border-radius: 100%;
                        position: absolute;
                        user-select: none;
                        transform: translate(-50%, -50%);
                    }
                    .left-top.btn {
                        cursor: se-resize;
                    }
                    .left.btn {
                        left: 0;
                        top: 50%;
                        height: 4px;
                        width: 16px;
                        border-radius: 4px;
                        transform: rotate(90deg) translate(-25%, 8px);
                        cursor: w-resize;
                    }
                    .right-top.btn {
                        left: 100%;
                        cursor: ne-resize;
                    }
                    .right.btn {
                        left: 100%;
                        top: 50%;
                        height: 4px;
                        width: 16px;
                        border-radius: 4px;
                        transform: rotate(90deg) translate(-25%, 8px);
                        cursor: w-resize;
                    }
                    .left-bottom.btn {
                        left: 0%;
                        top: 100%;
                        cursor: ne-resize;
                    }
                    .right-bottom.btn {
                        left: 100%;
                        top: 100%;
                        cursor: se-resize;
                    }
                    .delete.btn {
                        width: 18px;
                        height: 18px;
                        color: var(--pointColor);
                        font-size: 16px;
                        left: 50%;
                        top: -30px;
                        background-color: transparent;
                        cursor: pointer;
                    }
                    .delete.btn::before {
                        position: absolute;
                        left: 50%;
                        transform: translate(-50%, 0px);
                    }
                    .btn.rotate {
                        width: 18px;
                        height: 18px;
                        color: var(--pointColor);
                        font-size: 16px;
                        left: 50%;
                        bottom: -50px;
                        background-color: transparent;
                        //cursor: url(./_mouse-icon-rotate-0.svg) 12 12, auto;
                    }
                    .btn.rotate::before {
                        position: absolute;
                        left: 50%;
                        transform: translate(-50%, 0px);
                    }
                }
                .txt {
                    width: 100%;
                    height: 100%;
                    user-select: none;
                    cursor: default;
                    box-sizing: border-box;
                    outline: none;
                    word-break: break-all;
                }
            }
        }
        .bg-plate-bottom {
            background-image: url(./_background-transparent.png);
        }
    }
</style>

</html>

使用html2canvas生成的dom元素,其元素以及子元素尽量不要使用transform:translate;否则会出现绘制canvas定位显示问题
文件图片(_background-transparent):文件图片

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值