canvas+fabric实现自定义封面

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            margin: 0 auto;
        }
    </style>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.min.js"></script>
</head>

<body>
    <div>
        <button class="btn">点击</button>
        <button class="add-text">添加文案</button>
        <button class="to-base64">生成图片</button>
        <canvas id="canvas" width="500" style="border:1px solid black"></canvas>
    </div>
    <script>
        const btn = document.querySelector('.btn')
        const addText = document.querySelector('.add-text')
        const base64Image = document.querySelector('.to-base64')
        var canvas = document.getElementById("canvas")
        var ctx = canvas.getContext('2d');
        var left = 0

        // 实例化
        let fabricObj = new fabric.Canvas('canvas')
        //  设置画布宽高  可以动态设置画布宽高,如果在标签上也设置了宽高,则会将其覆盖掉
        fabricObj.setWidth(500)
        fabricObj.setHeight(500)
        // 设置背景图
        function setBackImage() {
            function setPictureBg(src) {
                const newImg = new Image();
                newImg.src = src;
                newImg.onload = () => {
                    fabricObj.setBackgroundImage(src, fabricObj.renderAll.bind(fabricObj), {
                        scaleX: fabricObj.width / newImg.width,
                        scaleY: fabricObj.height / newImg.height,
                        crossOrigin: 'anonymous'
                    });
                };
            }
            setPictureBg('https://sput.xwabx.com/file/background/1/image_02.png')

            let num = -1
            const urls = [
                'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
                'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
                'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
                'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
                'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
                'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
                'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg',
            ]
            btn.onclick = () => {
                if (num == 6) {
                    num = -1
                }
                num++
                setPictureBg(urls[num])
            }
        }
        setBackImage()


        var count = 1
        var arr = [`text${count}`]
        function setTextBorder() {
            function setTextStyle(cur) {
                // 创建文本对象并设置相关属性
                cur = new fabric.Textbox(
                    '阿里士大夫艰苦', {
                    lineHeight: 1.2,
                    left: 5,
                    top: 40,
                    fontSize: 40,
                    fontFamily: 'HanKangLiJinhei',
                    fill: '#000',
                    stroke: 'blue', // 设置描边颜色为黑色
                    strokeWidth: 1, // 设置描边宽度为3像素
                    textAlign: 'center',
                    editable: false, // 不能编辑
                    hasControls: false, //没有控制角,只能移动操作
                    splitByGrapheme: true, //文字自动换行
                    lockScalingY: true, // 禁止Y轴伸缩
                    // lockMovementX: true //禁止横向移动

                }
                );
                // 将文本添加到画布上
                fabricObj.add(cur);
                cur.on('moving', function () {
                    movingFn(cur)
                });
            }
            setTextStyle(arr[0])

            // 添加文案
            addText.onclick = () => {
                count++
                arr.push(`text${count}`)
                setTextStyle(arr[count - 1])
            }
        }
        setTextBorder()


        // 移动操作限制
        function movingFn(currentText) {
            const { width: cWidth, height: cHeight } = canvas.style;
            const { width: fWidth, height: fHeight, left, top } = currentText;

            let isOutSide = false;
            //超出左边界
            if (left < 0) {
                currentText.left = 10;
                isOutSide = true;
            }
            // 超出右边界
            if (left + fWidth >= Number(cWidth.slice(0, -2))) {
                currentText.left = Number(cWidth.slice(0, -2)) - fWidth - 10;
                isOutSide = true;
            }
            // 超出上边界
            if (top <= 0) {
                currentText.top = 0;
                isOutSide = true;
            }
            // 超出下边界
            if (top + fHeight > Number(cHeight.slice(0, -2))) {
                currentText.top = Number(cHeight.slice(0, -2)) - fHeight - 10;
                isOutSide = true;
            }

            isOutSide && fabricObj.renderAll();
        }


        base64Image.onclick = () => {
            const base64 = canvas.toDataURL({
                format: 'png',
                quality: 1
            })
            console.log(base64);
        }

        let timer
        window.onresize = () => {
            if (timer) {
                clearTimeout(timer)
            }
            timer = setTimeout(() => {
                const { innerHeight, innerWidth } = window
                let objects = fabricObj.getObjects();
                canvas.style.width = innerWidth - 100 + 'px'
                canvas.style.height = innerHeight - 100 + 'px'
                fabricObj.setWidth(canvas.style.width.slice(0, -2));
                fabricObj.setHeight(canvas.style.height.slice(0, -2));
                fabricObj.remove.apply(fabricObj, objects);
                resizeCanvasFn(objects)
                console.log(canvas.style.width);

                console.log('尺寸发生了变化');
            }, 1000)
        }

        function resizeCanvasFn(objects) {
            // 更新所有对象的位置和大小
            const { width, height } = canvas.style
            for (let i = 0; i < objects.length; i++) {
                let object = objects[i];
                if (object.isType('image')) {
                    object.set({
                        left: width.slice(0, -2) - object.width * 0.5 - 22,
                        top: 10
                    });
                } else {
                    object.set({
                        left: width.slice(0, -2) * 0.5 - object.width * 0.5,
                        top: object.top > height.slice(0, -2) ? height.slice(0, -2) - 40 : object.top
                    });
                }
            }
            //重新将所有对象添加到画布中;
            for (let i = 0; i < objects.length; i++) {
                fabricObj.add(objects[i]);
            }
            // fabricObj.setPictureBg('https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'); ///static/img/img.2b735807.png'
            // 设置新的背景图片路径或URL
            setBackImage()
            fabricObj.renderAll();
        }
    </script>
</body>

</html>