vue+element加入簽名效果(移動端)

最近根據公司項目需求作一個在線簽名,技術棧用的是vue+Element ui

想了想這... canvas我不太會,簡單畫線可還行...,想了想來唄,擼上

在網上找了不少效果,都不太無限接近效果,磕磕絆絆也算是找到了比較滿意的效果

需求是用element ui dialog彈框里加入簽名效果,期間也遇到不少問題,在這裏總結一下,也但願能有所幫助。

!------------------------------------------------------------------------------------------vue

下面介紹爲了方便就把項目的文件叫做父組件,而後簽名的那個組件叫做子組件

! 若有不太明白的地方,多看看代碼註釋。爲細節地方canvas

1. 首先根據element ui 在父組件中設置好diglog彈框,而且在全局樣式下,自定義樣式

<div class="canva" @click="centerDialogVisible = true">
// click綁定的方法是element提供的 centerDialogVisibe=true  是點擊時彈框出現
            <img :src="imgsrc" alt=""/>  // src = base64 ,下面介紹到
</div>
// div是在父組件中,因此有了下面子傳給父數據

// 而後設置dialog彈框基本樣式
// title爲彈框中頭部出現的名字
// visible.sync 爲click綁定的方法同樣
// width爲整個dialog的寬度
// <sign></sign>是簽名組件,綁定的方法是自定義方法,子傳父,後面會詳細介紹
<el-dialog
            title="簽名"
            :visible.sync="centerDialogVisible"
            width="85%"
            center>
            <sign @draw_save="getSignImg"></sign>
</el-dialog>

//而後在全局樣式下自定義彈框中默認的內容高度

.el-dialog {
    .el-dialog__header{
        height: 20px;
    }
    
    .el-dialog__body{
        height: 400px;
        overflow: auto;  // 項目中其餘dialog須要滾動條,因此加上就會出現滾動條。簽名可忽略
    }
}
.el-dialog__wrapper .el-dialog__title{
    font-size: 21px;
}
複製代碼

2. 而後在父組件data中定義centerDialogVisibe=false,imgsrc=''

data(){
    return{
        imgsrc: '', // base64編碼,保存爲圖片用到
        centerDialogVisible: false //dialog彈框顯示 fales不顯示,true顯示
    }
}
複製代碼

3. 而後dialog彈框的樣式寫好以後,就該引入組件了,組件是在網上找的,原文地址以下

原文地址是組件下載地址,並無過多介紹 download.csdn.net/download/we…bash

組件爲單獨組件,經過components引入便可使用,根據項目需求自行配置編寫樣式。看成子組件引入父組件中。

組件內容以下:

<template>
  <div class="sign">
    <canvas id="canvas" :width="width" :height="height"></canvas>
    <div>
      <button type="button" @click="clear" id="clear">清空</button>
      <button type="button" @click="save" id="save">保存</button>
    </div>
  </div>
</template>

<script>
/*
  * width   canvas 寬度
  * height  canvas 高度
  * strokeStyle  線條顏色
  * showUrl   是否顯示預覽圖片
  * imgWidth  img 寬度
  * imgHeight img 高度
  * draw_clear   //監聽清空事件
  * draw_save    //監聽保存事件 返回base64 img 路徑
  * */
var preHandler = function (e) { e.preventDefault() }
export default {
  name: 'drawSign',
  props: {
    width: {
      type: String,
      default: '565'
    },
    height: {
      type: String,
      default: '355'
    },
    strokeStyle: {
      type: String,
      default: '#000'
    },
    showUrl: {
      type: Boolean,
      default: true
    },
    imgWidth: {
      type: String,
      default: '240'
    },
    imgHeight: {
      type: String,
      default: '106'
    }
  },
  data () {
    return {
      canvas: null, // canvas
      ctx: null, // ctx canvas對象
      stroke_info: null, // 當前繪圖的座標
      url: '' // base64 圖像
    }
  },
  methods: {
    init () {
      let that = this
      this.canvas = document.getElementById('canvas')
      this.ctx = this.canvas.getContext('2d')
      this.stroke_info = this.canvas.getBoundingClientRect()
      this.canvas.addEventListener('touchstart', function (event) {
        document.addEventListener('touchStart', preHandler, false)
        that.darwStart(event)
      })
      this.canvas.addEventListener('touchend', function (event) {
        document.addEventListener('touchend', preHandler, false)
        that.drawEnd()
      })
      this.clear()
    },
    darwStart (e) {
      let that = this
      let t = e.changedTouches[0]
      // console.log(t.clientX, t.clientY);
      this.ctx.strokeStyle = this.strokeStyle
      this.ctx.beginPath() // 清空全部繪畫路徑
      this.ctx.moveTo(t.clientX - this.stroke_info.left, t.clientY - this.stroke_info.top)
      this.canvas.addEventListener('touchmove', function (event) {
        that.darwMove(event)
      })
    },
    darwMove (e) {
      let t = e.changedTouches[0]
      this.ctx.lineTo(t.clientX - this.stroke_info.left, t.clientY - this.stroke_info.top)
      this.ctx.stroke()
    },
    drawEnd () {
      document.removeEventListener('touchstart', preHandler, false)
      document.removeEventListener('touchmove', preHandler, false)
      document.removeEventListener('touchend', preHandler, false)
    },
    clear () {
      this.ctx.clearRect(0, 0, this.width, this.height)
      this.url = ''
      this.$emit('draw_clear')
    },
    save () {
      console.log(this)
      let data = this.canvas.toDataURL()
      // let query = {url: data}
      this.$emit('draw_save', data)  
      // $emit 傳data給父組件,當簽名簽完了以後,會保存圖片的,data是base64編碼,圖片img src直接可識別
      // console.log(this.canvas);
    }
  },

  mounted () {
    this.$nextTick(_ => {
      this.init()
    })
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

  #clear,#save{
   width:270px;
   height:50px;
   line-height:50px;
   font-size:20px;
   position:absolute;
  }
  #clear{
   bottom:0;
  }
  #save{
   bottom:0;
   right:0;
  }
</style>

複製代碼

4. 而後在父組件methods中寫方法接收子組件傳來的data

// 如上標籤中加入的自定義方法
getSignImg (val) {
     //val 是接收子組件的data的
      this.imgsrc = val  // 讓籤的名變成圖片
      this.centerDialogVisible = false 
    }
複製代碼

子組件有中帶有兩個按鈕,一個是清除,一個是肯定,點擊肯定時,圖片保存到原來須要的位置後,dialog應該關閉,因此加上了element ui 提供的

this.centerDialogVisible = false 
複製代碼

就能夠點擊肯定,關閉dialog彈框了app

總結:dom

  1. elemnet ui dailog彈框不要寫入 標籤內,要寫在根元素中,不要被包裹,以下結構可參考
</el-col>
          </el-row>
            <el-dialog
            title="簽名"
            :visible.sync="centerDialogVisible"
            width="85%"
            center>
            <sign @draw_save="getSignImg"></sign>
          </el-dialog>
        </div>
複製代碼
  1. 想要點擊某個元素出現dialog彈框時,就給某個元素加上element提供的點擊事件(),而後dialog中的定義(:visible.sync)也必須一致ui

  2. 在沒有引入組件以前,是在父組件中寫js代碼,由於dialog彈框出現時,彈框裏面的dom纔會加載,js會當即執行,用了其提供的open方法也不是很理想,js代碼總會比dom先執行一步,我也放在定時器中讓js緩慢執行,而後清除定時器又成了問題,因此就放棄了這種寫法,改成組件引入。this

  3. 若是某個元素綁定了element提供的點擊事件以後,想又得綁定一個點擊事件,那麼把提供的方法寫在本身的方法中編碼

<div class="canva" @click="isShow">

methods:{
    isShow(){
        this.centerDialogVisible = true
        //...
    }
}
複製代碼
  1. 想要改變canvas寬高,畫線粗細,畫線顏色,畫線背景,必定在子組件內props中更改,自定義改會出問題,canvas描線會模糊,有鋸齒url

  2. 父組件想要子組件中的data,就利用子傳父,$emit ,父組件得用子組件的data,保存爲圖片,子組件就得傳出去spa

而後以上就總結完畢,搜了好多文章,並無詳細的介紹簽名效果,有的是須要引入插件,有的是須要寫js,有的更是要充某幣購買,非常麻煩,而後再這裏寫上這篇文章,是爲了幫助更多的人,也許公司項目恰好也作這個效果呢,這些都有可能。不過還好下載的組件沒花錢,花錢買了,怪怪的,免費最好。

若是對你有幫助,煩請點個贊再走唄

相關文章
相關標籤/搜索