裁剪上傳圖片

張旭超發表於2023-03-02

使用vue3和elementPlus實現上傳圖片裁剪
參考文章地址:https://chengpeiquan.com/article/vue-picture-cropper.html#demo
image.png

<template>
  <!-- 選擇圖片 -->
  <br/>
  <label for="explore" class="labelBtn">
    <input
      style="display: none;"
      id="explore"
      ref="uploadInput"
      type="file"
      accept="image/jpg, image/jpeg, image/png, image/gif"
      @change="selectFile"
    />
    + 點選上傳封面圖片
  </label>
  {{ result.fileName }}
  <br/>
  <br/>
  <!-- 選擇圖片 -->
  <!-- 結果預覽區 -->
  <div v-if="result.dataURL && result.blobURL">
    <p>裁切後的 Base64 圖片預覽:</p>
    <div class="preview">
      <img :src="result.dataURL" alt="組合式 API" />
    </div>
    <p>裁切後的 Blob 圖片預覽:</p>
    <div class="preview">
      <img :src="result.blobURL" alt="組合式 API" />
    </div>
    <p>可以按 F12 檢視列印的 base64 / blob / file 結果</p>
  </div>
  <!-- 結果預覽區 -->

  <!-- 用於裁切的彈窗 -->
  <el-dialog v-model="isShowDialog" title="圖片裁切" :close-on-click-modal="false">
    <template #footer>
      <el-button @click="isShowDialog = false; result.fileName = ''">取消</el-button>
      <el-button @click="clear">清除</el-button>
      <el-button @click="reset">重置</el-button>
      <el-button type="primary" @click="getResult">裁切</el-button>
    </template>

    <!-- 圖片裁切外掛 -->
    <VuePictureCropper
      :boxStyle="{
        width: '100%',
        height: '100%',
        backgroundColor: '#f8f8f8',
        margin: 'auto',
      }"
      :img="pic"
      :options="{
        viewMode: 1,
        dragMode: 'crop',
        aspectRatio: 16 / 9,
      }"
    />
    <!-- 圖片裁切外掛 -->
  </el-dialog>
  <!-- 用於裁切的彈窗 -->
</template>

<script setup>
import { reactive, ref } from 'vue'
import VuePictureCropper, { cropper } from 'vue-picture-cropper'
const isShowDialog = ref(false)
const uploadInput = ref(null)
const pic = ref('')
const result = reactive({
  dataURL: '',
  blobURL: '',
  fileName: ''
})
/**
 * 選擇圖片
 */
const selectFile = (e) => {
  // 重置上一次的結果
  result.dataURL = ''
  result.blobURL = ''
  // 如果有多個裁剪框,也需要重置掉裁剪目標的值,避免使用同一張圖片無法觸發watch
  pic.value = ''
  // 獲取選取的檔案
  const target = e.target
  const { files } = target
  if (!files) return
  const file = files[0]
  result.fileName = file.name
  // 轉換為base64傳給裁切元件
  const reader = new FileReader()
  reader.readAsDataURL(file)
  reader.onload = () => {
    // 更新裁切彈窗的圖片源
    pic.value = String(reader.result)
    // 顯示裁切彈窗
    isShowDialog.value = true
    // 清空已選擇的檔案
    if (!uploadInput.value) return
    uploadInput.value.value = ''
  }
}
/**
 * 獲取裁切結果
 */
const getResult = async () => {
  console.log(cropper)
  // 獲取生成的base64圖片地址
  const base64 = cropper.getDataURL()
  // 獲取生成的blob檔案資訊
  const blob = await cropper.getBlob()
  // 獲取生成的file檔案資訊
  const file = await cropper.getFile({
    fileName: result.fileName
  })
  console.log({ base64, blob, file })
  // 把base64賦給結果展示區
  result.dataURL = base64
  try {
    result.blobURL = URL.createObjectURL(blob)
  } catch (e) {
    result.blobURL = ''
  }
  // 隱藏裁切彈窗
  isShowDialog.value = false
  result.fileName = ''
}
/**
 * 清除裁切框
 */
const clear = () => {
  cropper.clear()
}
/**
 * 重置預設的裁切區域
 */
const reset = () => {
  cropper.reset()
}
</script>
<style scoped>
.labelBtn {
  background: #fff;
  border: 1px solid #eee;
  border-radius: 5px;
  padding: 10px 20px;
}
</style>

相關文章