Browse Source

feat: Signature组件

songchenglin3 5 years ago
parent
commit
2e01945891

File diff suppressed because it is too large
+ 557 - 539
src/config.json


+ 4 - 1
src/nutui.js

@@ -104,6 +104,8 @@ import LuckDraw from "./packages/luckdraw/index.js";
 import "./packages/luckdraw/luckdraw.scss";
 import Video from "./packages/video/index.js";
 import "./packages/video/video.scss";
+import Signature from "./packages/signature/index.js";
+import "./packages/signature/signature.scss";
 
 const packages = {
   Cell,
@@ -156,7 +158,8 @@ const packages = {
   LeftSlip,
   TabSelect: TabSelect,
   LuckDraw: LuckDraw,
-  Video: Video
+  Video: Video,
+  Signature: Signature
 };
 
 const components = {};

+ 29 - 0
src/packages/signature/__test__/signature.spec.js

@@ -0,0 +1,29 @@
+import { shallowMount, mount } from '@vue/test-utils'
+import Signature from '../signature.vue';
+import Vue from 'vue';
+
+HTMLCanvasElement.prototype.getContext = () => { 
+    // return whatever getContext has to return
+};
+
+describe('Signature.vue', () => {
+    const wrapper = mount(Signature, {
+        propsData: { 
+            customClass: 'signature-wrap'
+        }
+    });
+    it('设置自定义class', () => {
+        return Vue.nextTick().then(function() {
+            expect(wrapper.find('.nut-signature').classes()).toContain('signature-wrap');
+        });
+    });
+
+    /* it('自定义不支持Canvas情况下的展示文案', () => {
+        wrapper.setProps({
+            unSupportTpl: '当前不可使用' 
+        });
+        return Vue.nextTick().then(function () {
+            expect(wrapper.find('nut-signature-unsopport').text()).toBe('当前不可使用');
+        })
+    }); */
+});

+ 63 - 0
src/packages/signature/demo.vue

@@ -0,0 +1,63 @@
+<template>
+    <div>
+        <h4>基本用法</h4>
+        <p>默认</p>
+        <p><nut-signature  @confirm="confirm" @clear="clear"></nut-signature></p>
+        <p class="demo-tips demo1">Tips: 点击确认按钮,下方显示签名图片</p>
+        <p class="margin-top">修改签字颜色和画笔粗细</p>
+        <p><nut-signature  @confirm="confirm1" @clear="clear1" :lineWidth="lineWidth" :strokeStyle="strokeStyle"></nut-signature></p>
+        <p class="demo-tips demo2">Tips: 点击确认按钮,下方显示签名图片</p>
+    </div>
+</template>
+
+<script>
+export default {
+    data(){
+        return{
+            lineWidth: 4,
+            strokeStyle: 'green'
+        }
+    },
+    computed:{
+
+    },
+    methods:{
+        confirm(canvas, data) {
+            let img = document.createElement('img');
+            img.src = data;
+            document.querySelector('.demo1').appendChild(img);
+        },
+
+        clear() {
+            let img = document.querySelector('.demo1 img'); 
+            if (img) {
+                img.remove();
+            }
+        },
+
+        confirm1(canvas, data) {
+            let img = document.createElement('img');
+            img.src = data;
+            document.querySelector('.demo2').appendChild(img);
+        },
+
+        clear1() {
+            let img = document.querySelector('.demo2 img'); 
+            if (img) {
+                img.remove();
+            }
+        },
+    }
+}
+</script>
+
+<style lang="scss">
+.demo-tips{
+    padding: 0.22rem 0;
+    font-size: 0.24rem;
+}
+.margin-top{
+  margin-top: 30px;
+}
+</style>
+

+ 89 - 0
src/packages/signature/doc.md

@@ -0,0 +1,89 @@
+# Scroller 滚动
+
+局部滚动组件,支持惯性、吸边回弹。纵向可支持下拉刷新和上拉加载,横向可支持滚动末尾跳转。
+
+## 基本用法
+
+默认
+```html
+<nut-signature  
+    @confirm="confirm" 
+    @clear="clear"
+></nut-signature>
+<p class="demo-tips demo">Tips: 点击确认按钮,下方显示签名图片</p>
+```
+```javascript
+export default {
+    data(){
+        return{
+        }
+    },
+    methods:{
+        confirm(canvas, data) {
+            let img = document.createElement('img');
+            img.src = data;
+            document.querySelector('.demo').appendChild(img);
+        },
+
+        clear() {
+            let img = document.querySelector('.demo img'); 
+            if (img) {
+                img.remove();
+            }
+        }
+    }
+}
+```
+
+修改签字颜色和画笔粗细
+
+```html
+<nut-signature  
+    @confirm="confirm1" 
+    @clear="clear1" 
+    :lineWidth="lineWidth" 
+    :strokeStyle="strokeStyle"
+></nut-signature>
+<p class="demo-tips demo">Tips: 点击确认按钮,下方显示签名图片</p>
+```
+```javascript
+export default {
+    data(){
+        return{
+            lineWidth: 4,
+            strokeStyle: 'green'
+        }
+    },
+    methods:{
+        confirm(canvas, data) {
+            let img = document.createElement('img');
+            img.src = data;
+            document.querySelector('.demo').appendChild(img);
+        },
+
+        clear() {
+            let img = document.querySelector('.demo img'); 
+            if (img) {
+                img.remove();
+            }
+        }
+    }
+}
+```
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| custom-class | 自定义class | String | -
+| line-width | 线条的宽度 | Number | 3
+| stroke-style | 绘图笔触颜色 | String | '#000'
+| type | 图片格式 | String | 'png'
+| un-supportT-tpl | 不支持Canvas情况下的展示文案 | String | '对不起,当前浏览器不支持Canvas,无法使用本控件!'
+
+## Event
+
+| 字段 | 说明 | 回调参数 
+|----- | ----- | ----- 
+| confirm | 点击确认按钮触发事件回调函数 | canvas和签名图片展示的 data URI
+| clear | 点击重签按钮触发事件回调函数 | 无

+ 8 - 0
src/packages/signature/index.js

@@ -0,0 +1,8 @@
+import Signature from './signature.vue';
+import './signature.scss';
+
+Signature.install = function(Vue) {
+  Vue.component(Signature.name, Signature);
+};
+
+export default Signature

+ 13 - 0
src/packages/signature/signature.scss

@@ -0,0 +1,13 @@
+.nut-signature{
+    .nut-signature-inner{
+        height: 10rem;
+        margin-bottom: 1rem;
+        border: 1px solid $border-color-base;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+    }
+    .nut-signature-unsopport{
+        font-size: $font-size-base;
+    }
+}

+ 136 - 0
src/packages/signature/signature.vue

@@ -0,0 +1,136 @@
+<template>
+    <div class="nut-signature" :class="customClass">
+        <div class="nut-signature-inner" ref="wrap">
+            <canvas ref="canvas" :height="canvasHeight" :width="canvasWidth" v-if="isCanvasSupported"></canvas>
+            <p class="nut-signature-unsopport" v-else>{{unSupportTpl}}</p>
+        </div>
+        <slot></slot>
+        <nut-button type="red" shape="circle" small @click="clear()">重签</nut-button>
+        <nut-button shape="circle" small @click="confirm()">确认</nut-button>
+    </div>
+</template>
+<script>
+import NutButton from "../button/button.vue";
+import "../button/button.scss";
+export default {
+    name:'nut-signature',
+    props: {
+        customClass:  {
+            type: String,
+            default: ''
+        },
+	    lineWidth:  {
+            type: Number,
+            default: 2
+        },
+	    strokeStyle:   {
+            type: String,
+            default: '#000'
+        },
+	    type: {
+            type: String,
+            default: 'png'
+        },
+	    unSupportTpl: {
+            type: String,
+            default: '对不起,当前浏览器不支持Canvas,无法使用本控件!'
+        }
+    },
+    data() {
+        return {
+        	canvasHeight: 0,
+            canvasWidth: 0,
+            ctx: null,
+            isSupportTouch : ('ontouchstart' in window),
+            events: ('ontouchstart' in window) ? ['touchstart', 'touchmove', 'touchend'] : ['mousedown', 'mousemove', 'mouseup']
+        };
+    },
+    components: {
+        'nut-button': NutButton
+    },
+    computed: {
+		isCanvasSupported() {
+	        let elem = document.createElement('canvas');
+	        return !!(elem.getContext && elem.getContext('2d'));
+	    },
+    },
+
+    methods: {
+	    addEvent() {
+	        this.startEventHandler =  this.startEventHandler.bind(this),
+	        this.$refs.canvas.addEventListener(this.events[0], this.startEventHandler, false);
+	    },
+
+	    startEventHandler(event) {
+            event.preventDefault();
+            
+	        this.ctx.beginPath();
+	        this.ctx.lineWidth = this.lineWidth;
+	        this.ctx.strokeStyle = this.strokeStyle;
+	        this.moveEventHandler=  this.moveEventHandler.bind(this),
+	        this.endEventHandler= this.endEventHandler.bind(this)
+	        this.$refs.canvas.addEventListener(this.events[1], this.moveEventHandler, false);
+	        this.$refs.canvas.addEventListener(this.events[2], this.endEventHandler, false);
+
+	    },
+
+	    moveEventHandler(event) {
+            event.preventDefault();
+            
+	        let evt = this.isSupportTouch ? event.touches[0] : event;
+	        let coverPos = this.$refs.canvas.getBoundingClientRect();
+	        let mouseX = evt.clientX  - coverPos.left;
+	        let mouseY = evt.clientY  - coverPos.top;
+
+	        this.ctx.lineTo(
+	            mouseX,
+	            mouseY
+	        );
+	        this.ctx.stroke();
+	    },
+
+	    endEventHandler(event) {
+	        event.preventDefault();
+
+	        this.$refs.canvas.removeEventListener(this.events[1], this.moveEventHandler, false);
+	        this.$refs.canvas.removeEventListener(this.events[2], this.endEventHandler, false);
+	    },
+
+	    clear(isUnEmit) {
+            this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+            this.ctx.closePath();
+            if (!isUnEmit) {
+                this.$emit('clear');
+            }
+        },
+
+	    confirm() {
+	        this.onSave(this.$refs.canvas);
+	    },
+
+	    onSave(canvas) {
+	        let dataurl;
+	        switch(this.type) {
+	            case 'png':
+	                dataurl = canvas.toDataURL('image/png');
+	                break;
+	            case 'jpg':
+	                dataurl = canvas.toDataURL('image/jpeg', 0.8);
+	                break;
+            }
+            this.clear(true);
+	        this.$emit('confirm', canvas, dataurl);
+    	}
+    },
+
+
+    mounted(){
+    	if(this.isCanvasSupported) {
+    		this.ctx = this.$refs.canvas.getContext('2d');
+	        this.canvasWidth = this.$refs.wrap.offsetWidth;
+	        this.canvasHeight= this.$refs.wrap.offsetHeight,
+			this.addEvent();
+    	}
+    }
+}
+</script>

+ 1 - 0
types/nutui.d.ts

@@ -71,3 +71,4 @@ export declare class Popup extends UIComponent {}
 
 export declare class LuckDraw extends UIComponent {}
 export declare class Video extends UIComponent {}
+export declare class Signature extends UIComponent {}