html手写板

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>
</head>

<body>
    <div id="app">
        <div class="sign-page">
            <div class="canvas-box">
                <div class="canvas" ontouchstart="methods.canvasTouchEvent(event,'canvasStart')"
                    ontouchmove="methods.canvasTouchEvent(event,'canvasMove')"
                    ontouchend="methods.canvasTouchEvent(event,'canvasEnd')">
                    <div class="title">请在该区域内工整书写您的签名</div>
                </div>
            </div>
            <p class="clearCanvas" onclick="methods.saveOrClear('clear')">清 除</p>
            <p class="saveCanvas" onclick="methods.saveOrClear('save')">保 存</p>
        </div>
    </div>
    <script>

        const temp = {
            canvas: null, // 画布el对象
            cxt: null, // 上下文
            stageInfo: null, // 返回canvas的大小及位置
            isSign: false //未签名提示
        }

        const data = new Proxy(temp, {
            set(target, property, value, receiver) {
                if (property === 'isSign') {
                    console.log(value);
                    document.querySelector('.title').style.display = value ? 'none' : 'block'
                }
                return Reflect.set(target, property, value);

            },
            get(target, key) {
                return Reflect.get(target, key);
            },
        })

        const methods = {
            /*
           *   画布初始化事件
           */
            initCanvas(obj) {
                data.canvas = document.createElement('canvas'); // 指定canvas
                obj.el.appendChild(data.canvas);
                data.cxt = data.canvas.getContext('2d'); // 设置2D渲染区域
                data.canvas.width = obj.el.clientWidth;
                data.canvas.height = obj.el.clientHeight;
                data.cxt.fillStyle = '#ffffff';
                data.cxt.strokeStyle = '#000000';
                data.cxt.fillRect(0, 0, data.canvas.width, data.canvas.width);
                data.cxt.lineWidth = 2;  // 设置线的宽度
                data.cxt.lineCap = 'round';
                data.stageInfo = data.canvas.getBoundingClientRect();
            },
            /*
            *   画布touch相关事件处理
            */
            canvasTouchEvent(e, type) {
                const cxt = data.cxt;
                const postion = [e.changedTouches[0].pageX - data.stageInfo.left, e.changedTouches[0].pageY - data.stageInfo.top]
                const handle = {
                    canvasStart: () => {
                        cxt.beginPath();
                        cxt.moveTo(...postion);
                    },
                    canvasMove: () => {
                        if (!e && !e.preventDefault) return;
                        e.preventDefault();
                        cxt.lineTo(...postion);
                        cxt.stroke();
                        data.isSign = true;
                    },
                    canvasEnd: () => cxt.closePath
                }
                handle[type]();
            },

            /*
            *  清除和保存事件
            */
            saveOrClear(type) {
                if (type === 'clear') {
                    data.cxt.clearRect(0, 0, data.canvas.width, data.canvas.height);
                    data.isSign = false;
                    return false;
                }

                if (data.isSign) {
                    const imgBase64 = data.canvas.toDataURL();
                    console.log(imgBase64);
                } else {
                    data.$dialog.alert({ title: '错误', message: '请绘制签名', messageAlign: 'center' });
                }
            }
        }

        const p = new Proxy(data, {
            set(target, property, value, receiver) {
                console.log(key);
                if (property === 'isSign') {
                    console.log('isSign');
                }
                return Reflect.set(target, key, value);

            }
        })

        setTimeout(() => {
            methods.initCanvas({ el: document.querySelector('.canvas') });
        })


    </script>
    <style>
        .canvas-box {
            width: calc(100% - 68px);
            height: calc(100% - 180px);
            margin-bottom: 38px;
            position: relative;
            border-radius: 6px;
            background: #fff;
            padding: 34px;

        }

        .canvas {
            background: #fff;
            height: 100%;
            width: 100%;
            border: 1px dashed #848588;
            position: relative;
            border-radius: 6px;
        }

        .saveCanvas,
        .clearCanvas {
            padding: 10px 0;
            background: rgba(207, 225, 245, 1);
            width: 45%;
            text-align: center;
            float: left;
            color: #3F8EE8;
        }

        .saveCanvas {
            margin-left: 10%;
        }

        .sign-page {
            background: #EDF1F6;
            width: calc(100% - 60px);
            height: calc(100% - 96px);
            padding: 58px 30px 38px;
            position: fixed;
            top: 0;
            left: 0;
        }

        .title {
            text-orientation: mixed;
            font-size: 18px;
            color: #A0ACBF;
            position: absolute;
            padding: 10%;
            top: 0;
            left: 0;
        }
    </style>
</body>

</html>

vue版

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <div class="sign-page">
            <div class="canvas-box">
                <div class="canvas" ref="canvas" @touchstart="canvasTouchEvent($event,'canvasStart')"
                    @touchmove="canvasTouchEvent($event,'canvasMove')" @touchend="canvasTouchEvent($event,'canvasEnd')">
                    <div class="title" v-if="!isSign">请在该区域内工整书写您的签名</div>
                </div>
            </div>
            <p class="clearCanvas" @click="saveOrClear('clear')">清 除</p>
            <p class="saveCanvas" @click="saveOrClear('save')">保 存</p>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>

        const app = new Vue({
            el: '#app',
            data: {
                canvas: null, // 画布el对象
                cxt: null, // 上下文
                stageInfo: null, // 返回canvas的大小及位置
                isSign: false //未签名提示
            },
            methods: {
                /*
               *   画布初始化事件
               */
                initCanvas(obj) {
                    this.canvas = document.createElement('canvas'); // 指定canvas
                    obj.el.appendChild(this.canvas);
                    this.cxt = this.canvas.getContext('2d'); // 设置2D渲染区域
                    this.canvas.width = obj.el.clientWidth;
                    this.canvas.height = obj.el.clientHeight;
                    this.cxt.fillStyle = '#ffffff';
                    this.cxt.strokeStyle = '#000000';
                    this.cxt.fillRect(0, 0, this.canvas.width, this.canvas.width);
                    this.cxt.lineWidth = 2;  // 设置线的宽度
                    this.cxt.lineCap = 'round';
                    this.stageInfo = this.canvas.getBoundingClientRect();
                },
                /*
                *   画布touch相关事件处理
                */
                canvasTouchEvent(e, type) {
                    const cxt = this.cxt;
                    const postion = [e.changedTouches[0].pageX - this.stageInfo.left, e.changedTouches[0].pageY - this.stageInfo.top]
                    const handle = {
                        canvasStart: () => {
                            cxt.beginPath();
                            cxt.moveTo(...postion);
                        },
                        canvasMove: () => {
                            if (!e && !e.preventDefault) return;
                            e.preventDefault();
                            cxt.lineTo(...postion);
                            cxt.stroke();
                            this.isSign = true;
                        },
                        canvasEnd: () => cxt.closePath
                    }
                    handle[type]();
                },

                /*
                *  清除和保存事件
                */
                saveOrClear(type) {
                    if (type === 'clear') {
                        this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
                        this.isSign = false;
                        return false;
                    }

                    if (this.isSign) {
                        const imgBase64 = this.canvas.toDataURL();
                        console.log(imgBase64);
                    } else {
                        this.$dialog.alert({ title: '错误', message: '请绘制签名', messageAlign: 'center' });
                    }
                }
            },
            mounted() {
                setTimeout(() => {
                    this.initCanvas({ el: this.$refs.canvas });
                })
            }
        })
    </script>
    <style>
        .canvas-box {
            width: calc(100% - 68px);
            height: calc(100% - 180px);
            margin-bottom: 38px;
            position: relative;
            border-radius: 6px;
            background: #fff;
            padding: 34px;

        }

        .canvas {
            background: #fff;
            height: 100%;
            width: 100%;
            border: 1px dashed #848588;
            position: relative;
            border-radius: 6px;
        }

        .saveCanvas,
        .clearCanvas {
            padding: 10px 0;
            background: rgba(207, 225, 245, 1);
            width: 45%;
            text-align: center;
            float: left;
            color: #3F8EE8;
        }

        .saveCanvas {
            margin-left: 10%;
        }

        .sign-page {
            background: #EDF1F6;
            width: calc(100% - 60px);
            height: calc(100% - 96px);
            padding: 58px 30px 38px;
            position: fixed;
            top: 0;
            left: 0;
        }

        .title {
            text-orientation: mixed;
            font-size: 18px;
            color: #A0ACBF;
            position: absolute;
            padding: 10%;
            top: 0;
            left: 0;
        }
    </style>
</body>

</html>
 

效果图

image.png

原文地址:https://www.cnblogs.com/dshvv/p/14102176.html