vue封装独立组件:实现手写签名功能

目录

第一章 效果展示

第二章 准备工作

2.1 使用的工具vue-sign

2.1.1 安装

2.1.2 了解

2.1.3 参数说明

第三章 源代码

第一章 效果展示

第二章 准备工作

2.1 使用的工具vue-esign

2.1.1 安装

npm install vue-esign --save

2.1.2 了解

  • 兼容pc端和移动端
  • 有对应的参数让我们自定义画布尺寸(导出图尺寸),画笔粗细、颜色,画布背景色
  • 能支持裁剪,在画布设定尺寸基础上裁掉四周空白部分

2.1.3 参数说明

属性 类型 默认值 说明
width Number 800 画布宽度,即导出图片的宽度
height Number 300 画布高度,即导出图片的高度
lineWidth Number 4 画笔粗细
lineColor String #000000 画笔颜色
bgColor String 画布背景色,为空时画布背景透明,
支持多种格式 '#ccc','#E5A1A1','rgb(229, 161, 161)','rgba(0,0,0,.6)','red'
isCrop Boolean false 是否裁剪,在画布设定尺寸基础上裁掉四周空白部分

第三章 源代码

  • 父组件
<el-col :span="13">
  <el-form-item label="被调查者签名" prop="respondentSign" :rules="[{
      type: 'string',
      required: true,
      message: '被调查者请签名',
      trigger: ['change']
    }]">
    <div 
      @click="signreVisible=true" 
      style="width: 400px;
      height: 150px;
      background-color: #d9d9d9;">
      <el-image 
        :src="inputForm.respondentSign"
        style="width: 400px;
          height: 150px;
          display: flex;
          align-items: center;
          justify-content: center;
          color: #999;">
        <div slot="error" >
           点击签名
        </div>
      </el-image>
    </div>
  </el-form-item>
</el-col>
<!--引用封装好的组件--->
<el-dialog title="被调查者签字" :visible.sync="signreVisible" width="700px">
  <sign @setsignin="setsignre"></sign>
</el-dialog>
<!---封装好的组件可以复用了-->
<el-dialog title="调查者签字" :visible.sync="signinVisible" width="700px">
   <sign @setsignin="setsignin"></sign>
</el-dialog>

// 引入自定义封装的组件
import sign from './component/sign.vue'

signreVisible: false,
inputForm:{
    respondentSign = ''
}

// 被调查者签字图片,获取子组件传的值
setsignre (img) {
  this.inputForm.respondentSign = img
  this.signreVisible = false
},
  • 子组件
<template>
  <div>
    <el-card class="qianming-container" body-style="padding:0px">
      <!---vue-esign组件-->
      <vue-esign
        ref="esign"
        :isCrop="isCrop"
        :width="600"
        :height="300"
        :lineWidth="lineWidth"
        :lineColor="lineColor"
        :format="'image/png'"
        :bgColor.sync="bgColor"
      ></vue-esign>
      <div class="contro-container">
        <el-button type="danger" @click="handleReset">清空画板</el-button>
        <el-button type="primary" @click="handleGenerate">确认签名</el-button>
      </div>
    </el-card>
  </div>
</template>
    
<script>
// 引入组件
import vueEsign from 'vue-esign'
// 这个是请求文件路径的接口
import fileService from '@/api/file/fileService.js'
export default {
  components: { vueEsign },
  name: 'sign',
  data () {
    return {
      lineWidth: 6,
      lineColor: '#000000',
      bgColor: '',
      resultImg: '',
      isCrop: false
    }
  },
  methods: {
    // 清空画板..
    handleReset () {
      this.$refs.esign.reset()
      this.resultImg = ''
    },
    // 生成签名图片..
    handleGenerate () {
      this.$refs['esign']
        .generate()
        .then((res) => {
          this.resultImg = res // 得到了签字生成的base64图片
          // console.log('resultImg', this.resultImg)
          // 这里直接传base64到父组件,然后在父组件处理数据调用接口
          // this.$emit('setsignin', res)
          // 也可以转换成在线地址
          const bl = this.dataURLtoFile(res)
          let formData = new FormData()
          formData.append('file', bl, Date.now() + '.png')
          // console.log('file', formData.get('file'))
          // 接口请求
          fileService.upload(formData).then((result) => {
            // 向父组件传已经转好的地址
            this.$emit('setsignin', result.data)
          })
        }).catch((err) => {
          // 没有签名,点击生成图片时调用
          alert(err + ' 未签名!')
        })
    },
    // 将base64转成blob流
    dataURLtoFile (urlData) {
      const type = 'image/png'
      let bytes = null
      if (urlData.split(',').length > 1) {
        bytes = window.atob(urlData.split(',')[1])
      } else {
        bytes = window.atob(urlData)
      }
      let ab = new ArrayBuffer(bytes.length)
      let ia = new Uint8Array(ab)
      for (let i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i)
      }
      return new Blob([ab], { type })
    }
  }
}
</script>
    
  <style scoped>
button {
  height: 40px;
}
.contro-container {
  width: 600px;
  height: 50px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-around;
  background-color: #d3d3d3;
  position: absolute;
  bottom: 0px;
}
.qianming-container {
  width: 600px;
  height: 350px;
  margin: 10px auto;
  position: relative;
}
.text {
  font-size: 14px;
}
.item {
  margin-bottom: 18px;
}
.clearfix:before,
.clearfix:after {
  display: table;
  content: '';
}
.clearfix:after {
  clear: both;
}
.box-card {
  width: 95%;
  margin-left: 2.5%;
  margin-top: 20px;
}
</style>
    

猜你喜欢

转载自blog.csdn.net/qq_45796592/article/details/133931066