vue 圖片上傳,圖片預覽

因爲項目是vue+vant,這裏圖片預覽直接使用vant的組件,不做多餘的封裝

html 結構

主要選擇圖片按鈕,圖片預覽區, 選擇圖片的input

<div class="img-upload">
    <ul class="preview-list" >
      <li
        class="img-item"
        v-for="(img, key) in fileList"
        :key="key"
        @click="() => imagePreviewShow = true"
      >
        <img class="preview-img" :src="img.base64" alt="img">
        <img
          :src="defImg"
          class="del-img"
          @click="delImg(img)"
        />
      </li>
      <li class="img-item" v-show="imgTotal < defCon.total">
        <label for="upload">
          <div slot="button">
            <div class="import-img-wrap">
              <span class="icon-add"><van-icon name="plus" /></span>
              <p class="text">添加圖片</p>
            </div>
          </div>
          <input
            ref="file"
            type="file"
            class="input-upload"
            id="upload"
            accept="image/*"
            @change="upload"
            :multiple="defCon.multiple"
          >
        </label>
      </li>
    </ul>
    <van-image-preview
      v-model="imagePreviewShow"
    :images="imgList">
    </van-image-preview>
  </div>

css 樣式

樣式文件有些冗餘,並沒有做優化,需要的話自己改改

<style lang="less">
.img-upload{
  &{
    position: relative;
    overflow: hidden;
  }
  .input-upload{
    position: absolute;
    left: -20rem /* 2000/100 */;
  }
  .preview-list{
    overflow: hidden;
    padding: .15rem /* 15/100 */ 0;
    .img-item{
      float: left;
      width: .8rem /* 80/100 */;
      height: .8rem /* 80/100 */;
      border-radius: .06rem /* 6/100 */;
      margin: 0 .15rem /* 10/100 */ .1rem /* 10/100 */ 0;
    }
    .preview-img{
      width: .8rem /* 80/100 */;
      height: .8rem /* 80/100 */;
    }
    .del-img{
      position: absolute;
      width: .24rem /* 24/100 */;
      height: .24rem /* 24/100 */;
      transform: translate(-.1rem, -.1rem);
    }
  }
  .import-img-wrap{
    margin: .32rem /* 32/100 */ 0;
    width: .8rem /* 80/100 */;
    height: .8rem /* 80/100 */;
    text-align: center;
    font-size:12px;
    overflow: hidden;
    font-weight:400;
    color:rgba(23,7,7,0.45);
    .import-img-input{
      transform: translateX(20000px);
    }
    .icon-add{
      display: inline-block;
      width: .26rem /* 26/100 */;
      height: .26rem /* 26/100 */;
      background: #999;
      font-size: .22rem /* 24/100 */;
      font-weight: 700;
      color: #fff;
      border-radius: .13rem /* 13/100 */;
    }
  }
}
</style>

js部分

整個js部分大概如下

  1. 常用配置, config
  2. data,常用配置信息,以及依賴屬性
  3. 函數調用
    a) uoload, 選擇文件後觸發,
    b) 然後裏邊對文件進行處理:壓縮, this.compressData;
    c) 轉換爲formdata, this.processFormData => 上傳圖片 this.uploadImg
    d) 將文件添加到fileList
    e) 上傳圖片 this.uploadImg: 圖片上傳後出發回調 =>this.handleUploadEnd
    f) handleUploadEnd> 根據狀態進行處理,上傳等待上傳的文件
    以上是代碼的大概執行過程和對應的函數
import defImg from '@/assets/images/del.png' // 刪除圖片,可以換成iconfont
import { getOssSign } from '../pages/api' // 後臺獲取阿里雲配置
import EXIF from 'exif-js' // 針對移動端圖片做處理, 橫豎的問題
import OSS from 'ali-oss' // ali-oss 插件,上傳使用
import md5 from '../utils/md5' // 文件命名
export default {
  name: 'img-upload',
  props: {
    config: {
      // 最大上傳限制
      maxSize: {
        type: Number,
        default: 10
      },
      // 壓縮比例
      compressionRatio: {
        type: Number,
        default: 50
      },
      // 是否壓縮
      compress:{
        type: Boolean,
        default: true
      },
      // 是否壓縮
      total:{
        type: Number,
        default: 5
      },
      // 是否立即上傳
      isUpdated:{
        type: Boolean,
        default: true
      },
      name: { // 上傳需要的
        type: String,
        default: 'file'
      },
      // 最大同時上傳數量
      maxUploadSize: {
        type: Number,
        default: 5
      }
    }
  },
  data() {
    return {
      fileList: [], // 保存文件列表,雙向綁定的時候會用到
      imgTotal: 0, // 當前文件最大數量
      defCon: {
        maxSize: 10, // more大小 m
        compressionRatio: 71, // 默認壓縮比
        compress: true, // 是否需要壓縮
        multiple: false, // 是否多選
        total: 5, // 最大數量
        orientation: false, // 是否有橫豎過程
        drawHeight: 80, // 如果需要限制文件寬高,默認高度
        drawWidth: 80,
        isUpdated: true, // 是否立即上傳
        name: 'file', // 
        maxUploadSize: 5 // 最大同時上傳
      },
      defImg,
      uploadQueue: [], // 上傳列表
      uploadWaiting: [], // 等待上傳列表
      uploadingQueue: new Set(), // 正在上傳的隊列
      upLoadingError: new Set(), // 上傳失敗列表
      timmer: 0,
      errorTip: false,
      timer: 0,
      headers: {},
      sigin: null, // 雲存儲簽名
      client : null, // 雲存儲實例
      imagePreviewShow: false // 控制圖片預覽艦
    }
  },
  mounted() {
    this.getSign()
  },
  methods: {
    async upload(e){
      let list = e.target.files || e.dataTransfer.files
      if (!list.length) return
      list = Array.from(list)
      if (this.imgTotal > this.defCon.total) {
        return this.$toast(`最多支持上傳${this.defCon.total}張照片`)
      }
      // 如果用戶選擇的文件數大於最大數量 截取
      if (list.length + this.imgTotal >  this.defCon.total) {
        list = list.slice(0, this.defCon.total - this.imgTotal)
      }
      // 處理回調
      let proList = await list.map(file => this.transformFileToBase64(file))
      // 處理結果
      Promise.all(proList)
        .then(arr => {
          return arr.map((item, key) => {
            let { base64, orientation } = item
            let file = list[key]
            return this.initItem(file, base64, orientation)
          })
        })
        .then(fileList => { // 壓縮圖片
          // 如果不需要壓縮,直接返回
          if (!this.defCon.compress) {
            return fileList
          }
          // 壓縮圖片
          let list = fileList.map(file => this.compressData(file))
          return Promise.all(list)
          // console.log('fileList', list)
        }).then(fileList => {
          if (this.defCon.isUpdated) {
            fileList.map(file => this.processFormData(file))
          }
          return fileList
        }).then(fileList => {
          this.fileList = this.fileList.concat(fileList)
          this.imgTotal =  this.fileList.length
        })
      
    },
    /**
     * 處理文件流
     * @param file
     * @returns {Promise<any>}
     */
    transformFileToBase64(file) {
      /**
       * 圖片上傳流程的第一步
       * @param data file文件
       */
      return new Promise((resolve) => {
        let orientation = null
        const reader = new FileReader()

        reader.onload = (e) => {
          const base64 = e.target.result
          if (file.type.indexOf('image') > -1) {
            EXIF.getData(file, function () {
              EXIF.getAllTags(this)
              orientation = EXIF.getTag(this, 'Orientation')
              resolve({ base64, orientation })
            })
          } else {
            resolve({ base64, orientation })
          }
        }
        reader.readAsDataURL(file)
      })
    },
    /**
     * @desc 初始化
     */
    initItem(file, base64, orientation){
      const item = {
        uid:  this.getUid(),
        status: this.upload ? 1 : 0, // 0 未開始,1 準備上傳,2 上傳成功,3 上傳失敗, -1 正在上傳
        imgKey: '', // 服務器返回的唯一key
        name: file.name, // 文件名稱
        size: file.size, // 文件大小
        type: file.type, // 文件類型
        file, // 文件流
        base64, // 沒有壓縮前的base64
        progress: 0, // 當前文件上傳進度
        compressBase64: null, // 轉換之後的base64
        response: {},
        orientation // 圖片的方向
      }
      if (item.size > this.defCon.maxSize * 1024 * 1024 ) {
        this.$emit('uploadError', 'overSize')
        if (this.showErrorToast) {
          this.showToast(`文件最大可上傳${this.defCon.maxSize}MB`)
        }
        return
      }
      return item
    },
    getUid() {
      this.imgTotal = this.imgTotal + 1
      return `upload-${new Date().getTime()}-${this.imgTotal}`
    },
    /**
     * 處理圖片
     * @param data
     * @param callback
     */
    compressData(data) {
      /**
       * 壓縮圖片
       * @param data file文件 數據會一直向下傳遞
       * @param callback 下一步回調
       */
      const self = this
      const orientation = data.orientation
      return new Promise((resolve) => {
        const img = new Image()
        img.src = data.base64
        img.onload = function() {
          let drawWidth = 0
          let drawHeight = 0

          drawWidth = this.naturalWidth
          drawHeight = this.naturalHeight

          // 改變一下圖片大小
          let maxSide = Math.max(drawWidth, drawHeight)
          if (maxSide > self.maxImageSize) {
            let minSide = Math.min(drawWidth, drawHeight)
            minSide = parseInt((minSide / maxSide * self.maxImageSize), 10)
            maxSide = self.maxImageSize
            if (drawWidth > drawHeight) {
              drawWidth = maxSide
              drawHeight = minSide
            } else {
              drawWidth = minSide
              drawHeight = maxSide
            }
          }
          
          resolve({
            img: this, 
            drawWidth,
            drawHeight,
            orientation,
            data
          })
        }
      }).then(this.compressCanvas)
    },
 
    /**
     * @desc 壓縮圖片
     * @param img 加載完成後的圖片
     * @param info 寬高, 是否需要處理旋轉
     */
    compressCanvas(info) {
      let { img, data } = info
      const compressionRatio = this.defCon.compressionRatio
      const compress = this.defCon.compress
      return new Promise((resolve) => {
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')
        const width = info.drawWidth
        const height = info.drawHeight
        canvas.width = info.drawWidth
        canvas.height = info.drawHeight
        // 判斷圖片方向,重置 canvas 大小,確定旋轉角度,iphone 默認的是 home 鍵在右方的橫屏拍攝方式
        switch (info.orientation) {
          // 1 不需要旋轉
          case 1: {
            ctx.drawImage(img, 0, 0, info.drawWidth, info.drawHeight)
            ctx.clearRect(0, 0, width, height)
            ctx.drawImage(img, 0, 0, width, height)
            break
          }
          // iphone 橫屏拍攝,此時 home 鍵在左側 旋轉180度
          case 3: {
            ctx.clearRect(0, 0, width, height)
            ctx.translate(0, 0)
            ctx.rotate(Math.PI)
            ctx.drawImage(img, -width, -height, width, height)
            break
          }
          // iphone 豎屏拍攝,此時 home 鍵在下方(正常拿手機的方向) 旋轉90度
          case 6: {
            canvas.width = height
            canvas.height = width
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            ctx.translate(0, 0)
            ctx.rotate(90 * Math.PI / 180)
            ctx.drawImage(img, 0, -height, width, height)
            break
          }
          // iphone 豎屏拍攝,此時 home 鍵在上方 旋轉270度
          case 8: {
            canvas.width = height
            canvas.height = width
            ctx.clearRect(0, 0, width, height)
            ctx.translate(0, 0)
            ctx.rotate(-90 * Math.PI / 180)
            ctx.drawImage(img, -width, 0, width, height)
            break
          }
          default: {
            ctx.clearRect(0, 0, width, height)
            ctx.drawImage(img, 0, 0, width, height)
            break
          }
        }
        let base64Url = ''
        if (compress) {
          base64Url = canvas.toDataURL(data.type, (compressionRatio / 100))
        } else {
          base64Url = canvas.toDataURL(data.type, 1)
        }
        data.compressBase64 = base64Url
        data.compressWidth = width
        data.compressHeight = height
        resolve(data)
      })
    },
    /**
     * 處理上傳數據
     * @param data
     */
    processFormData (data) {
      // 準備上傳數據
      let arr = data.compressBase64.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      data.blob = new Blob([u8arr], { type: mime })
      // data.status  1 等待上傳 2 上傳成功 3上傳失敗
      // 添加到 正在上傳列表 使
      this.uploadingQueue.add(data)
      this.uploadQueue.push(data)

      this.$emit('onChange', data, this.uploadQueue)
      // 當前上傳數量達到最大時,不在放入隊 等待上傳
      if (this.uploadingQueue.size < this.defCon.maxUploadSize) {
        this.uploadImg(data)
      } else {
        // 加入等待上傳
        this.uploadWaiting.push(data)
      }
      
    },
    /**
     * 上傳圖片
     * @param data
     */
    async uploadImg(data) {
      this.$emit('update:isUpdated', true)
      // 處理文件名
      let imgName = md5(`${data.uid}-${data.name}`)
      let imgKey = `ipxmall/${imgName}`
      
      this.client.put(imgKey, data.blob)
        .then(response => {
          // 上傳完畢回調
          let res = response.res
          if(res.status === 200) {
            data.imgKey = response.url
          }
          // 圖片前綴
          // console.log('response', response)
          this.handleUploadEnd(data, res, res.status) 
        })
    },
    // 上傳進度條
    handleProgress(data, e) {
      data.progress = parseInt((e.loaded / e.total) * 100, 10)
    },
    /**
     * @desc 提示處理上傳失敗的圖片
     */
    handleErrorUploadList() {
      let uploadErrs = this.uploadQueue.filter(item => item.status === 3)
      let len = uploadErrs.length
      if (len === 0 && this.uploadingQueue.size === 0) {
        this.$emit('onUploadEnd', this.uploadQueue)
        return false
      }
      this.$modal.confirm(`有${len}張圖片上傳失敗,是否重新上傳!`, '上傳失敗提示')
        .then(() => {
          uploadErrs.map((item, idx) => {
            item.status = 1
            if (idx < this.defCon.maxUploadSize) {
              this.uploadImg(item)
            }
          })
        }, () => {
          // 如果用戶不選擇繼續上傳,則從列表刪除該文件
          let uids = uploadErrs.map(item => item.uid)
          this.uploadQueue = this.fileList = this.fileList.filter(item => !uids.includes(item.uid))
    
          this.$emit('onUploadEnd', this.uploadQueue)
        })
    },
    /**
     * 處理成功結果
     * @param data
     * @param response
     */
    handleUploadEnd(data, response, status) {
      data.response = response
      data.status = status === 200 ? 2 : 3
      // eslint-disable-next-line no-debugger
      // debugger
      this.$emit('onChange', data, this.uploadQueue)
      // 上傳成功後從隊列中刪除
      if (status === 200) {
        this.uploadingQueue.delete(data)
      }
   
      
      // 處理等待上傳的
      if (this.uploadWaiting.length) {
        let uploadItem = this.uploadItem.shift()
        this.uploadingQueue.add(uploadItem)
        this.uploadImg(uploadItem)
      } 
      if (this.uploadingQueue.size === 0) {
        // 處理未上傳成功的
        this.handleErrorUploadList()
      }
    },
    /**
     * @desc 上傳圖片
     */
    delImg(delImg) {
      this.fileList = this.fileList.filter(item => delImg.uid !== item.uid)
      this.imgTotal -= 1
    },
    /**
     * @desc 獲取簽名
     */
    async getSign() {
      let { errorCode, data } = await getOssSign()
      if (errorCode === 0) {
        this.sign = data
        let {
          securityToken,
          accessKeyId,
          accessKeySecret,
          bucket,
          endpoint
        } = data
        // 創建實例
        let client  = new OSS({
          endpoint,
          accessKeyId,
          accessKeySecret,
          bucket,
          stsToken: securityToken
        })
        this.client  = client 
      }
      
    }
  },
  computed: {
    imgList() {
      return this.fileList.map(item => item.base64)
    }
  }
}

md5.js 內容

/* eslint-disable */
/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y) {
  var lsw = (x & 0xFFFF) + (y & 0xFFFF),
    msw = (x >> 16) + (y >> 16) + (lsw >> 16)
  return (msw << 16) | (lsw & 0xFFFF)
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt) {
  return (num << cnt) | (num >>> (32 - cnt))
}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t) {
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
}

function md5_ff(a, b, c, d, x, s, t) {
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t)
}

function md5_gg(a, b, c, d, x, s, t) {
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t)
}

function md5_hh(a, b, c, d, x, s, t) {
  return md5_cmn(b ^ c ^ d, a, b, x, s, t)
}

function md5_ii(a, b, c, d, x, s, t) {
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t)
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length.
 */
function binl_md5(x, len) {
  /* append padding */
  x[len >> 5] |= 0x80 << (len % 32)
  x[(((len + 64) >>> 9) << 4) + 14] = len

  var i, olda, oldb, oldc, oldd,
    a = 1732584193,
    b = -271733879,
    c = -1732584194,
    d = 271733878

  for (i = 0; i < x.length; i += 16) {
    olda = a
    oldb = b
    oldc = c
    oldd = d

    a = md5_ff(a, b, c, d, x[i], 7, -680876936)
    d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586)
    c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819)
    b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330)
    a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897)
    d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426)
    c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341)
    b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983)
    a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416)
    d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417)
    c = md5_ff(c, d, a, b, x[i + 10], 17, -42063)
    b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162)
    a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682)
    d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101)
    c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290)
    b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329)

    a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510)
    d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632)
    c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713)
    b = md5_gg(b, c, d, a, x[i], 20, -373897302)
    a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691)
    d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083)
    c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335)
    b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848)
    a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438)
    d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690)
    c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961)
    b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501)
    a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467)
    d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784)
    c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473)
    b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734)

    a = md5_hh(a, b, c, d, x[i + 5], 4, -378558)
    d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463)
    c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562)
    b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556)
    a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060)
    d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353)
    c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632)
    b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640)
    a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174)
    d = md5_hh(d, a, b, c, x[i], 11, -358537222)
    c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979)
    b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189)
    a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487)
    d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835)
    c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520)
    b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651)

    a = md5_ii(a, b, c, d, x[i], 6, -198630844)
    d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415)
    c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905)
    b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055)
    a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571)
    d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606)
    c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523)
    b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799)
    a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359)
    d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744)
    c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380)
    b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649)
    a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070)
    d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379)
    c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259)
    b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551)

    a = safe_add(a, olda)
    b = safe_add(b, oldb)
    c = safe_add(c, oldc)
    d = safe_add(d, oldd)
  }
  return [a, b, c, d]
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2rstr(input) {
  var i,
    output = ''
  for (i = 0; i < input.length * 32; i += 8) {
    output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF)
  }
  return output
}

/*
 * Convert a raw string to an array of little-endian words
 * Characters >255 have their high-byte silently ignored.
 */
function rstr2binl(input) {
  var i,
    output = []
  output[(input.length >> 2) - 1] = undefined
  for (i = 0; i < output.length; i += 1) {
    output[i] = 0
  }
  for (i = 0; i < input.length * 8; i += 8) {
    output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32)
  }
  return output
}

/*
 * Calculate the MD5 of a raw string
 */
function rstr_md5(s) {
  return binl2rstr(binl_md5(rstr2binl(s), s.length * 8))
}

/*
 * Calculate the HMAC-MD5, of a key and some data (raw strings)
 */
function rstr_hmac_md5(key, data) {
  var i,
    bkey = rstr2binl(key),
    ipad = [],
    opad = [],
    hash
  ipad[15] = opad[15] = undefined
  if (bkey.length > 16) {
    bkey = binl_md5(bkey, key.length * 8)
  }
  for (i = 0; i < 16; i += 1) {
    ipad[i] = bkey[i] ^ 0x36363636
    opad[i] = bkey[i] ^ 0x5C5C5C5C
  }
  hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8)
  return binl2rstr(binl_md5(opad.concat(hash), 512 + 128))
}

/*
 * Convert a raw string to a hex string
 */
function rstr2hex(input) {
  var hex_tab = '0123456789abcdef',
    output = '',
    x,
    i
  for (i = 0; i < input.length; i += 1) {
    x = input.charCodeAt(i)
    output += hex_tab.charAt((x >>> 4) & 0x0F) +
      hex_tab.charAt(x & 0x0F)
  }
  return output
}

/*
 * Encode a string as utf-8
 */
function str2rstr_utf8(input) {
  return unescape(encodeURIComponent(input))
}

/*
 * Take string arguments and return either raw or hex encoded strings
 */
function raw_md5(s) {
  return rstr_md5(str2rstr_utf8(s))
}

function hex_md5(s) {
  return rstr2hex(raw_md5(s))
}

function raw_hmac_md5(k, d) {
  return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))
}

function hex_hmac_md5(k, d) {
  return rstr2hex(raw_hmac_md5(k, d))
}

function md5(string, key, raw) {
  if (!key) {
    if (!raw) {
      return hex_md5(string)
    }
    return raw_md5(string)
  }
  if (!raw) {
    return hex_hmac_md5(key, string)
  }
  return raw_hmac_md5(key, string)
}
export default md5

結束

代碼比較多,還差以後後續上傳的方法沒有寫。。。。做個筆記

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章