Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money

H5 picture upload component: it can be used alone or embedded in the android native shell for interactive use with the mobile terminal. Component encapsulation based on input, complete permission issues, image upload, image compression, image to base64 format, base64 to Blob, etc

  1. Permissions problem: camera + storage dual permissions, camera photo, album access
  2. Picture upload: batch upload, upload multiple pictures at the same time
  3. Image compression: Use canvas compression
  4. Image preview: Image data is converted to Base64 format
  5. Duplicate image cannot be uploaded (clear input value)

Component packaging

<template>
  <div @click.stop="chooseType" class="upload-wrap">
    <slot name="upload">
      <div class="upload-item">
        <img src="/images/icon_upload.png" class="item-img" />
      </div>
    </slot>
    <input
      id="uploadIcon"
      ref="uploadIcon"
      @change="uploadImg($event)"
      type="file"
      accept="image/*"
      style="display: none;"
      capture="camera"
    />
  </div>
</template>

<script>
  export default {
    name: "UploadImage".props: {
      quality: {
        // Image quality
        type: Number.default: null,},width: {
        // Image width
        type: Number.default: null,},height: {
        // Image height
        type: Number.default: null,}},data() {
      return {
        picList: [],}; },methods: {}};</script>

<style lang="scss" scoped>
  .upload-wrap {
    .upload-item {
      width: 1.68 rem;
      height: 1.68 rem;
      border-radius: 0.12 rem;
      margin-right: 0.2 rem;
      position: relative;
      overflow: hidden;

      .item-img {
        width: 100%;
        height: 100%; }}}</style>
Copy the code

Permission problems

You need to interact with clients to obtain permissions. The permission parameters on our side are those that the client has mounted on the Window

export default {
  computed: {
    isApp() {
      return this.$store.state.nativePara.isApp; }},methods: {
    // After clicking, first check permissions
    chooseType() {
      // The client interactively obtains permissions
      if (this.getPermession()) {
        // Trigger the input click event after validation
        document.getElementById("uploadIcon").click(); }},getPermession() {
      // If it is in app
      if (this.isApp) {
        // Get camera permission
        const permission = window.xxx.checkPermission(
          "android.permission.CAMERA"
        );
        if (permission === 0) {
          // If not, request open
          window.xxx.requestPermission("android.permission.CAMERA");
          return false;
        }

        // Local storage permission
        const permission2 = window.xxx.checkPermission(
          "android.permission.WRITE_EXTERNAL_STORAGE"
        );
        if (permission2 === 0) {
          // If not, request open
          window.xxx.requestPermission(
            "android.permission.WRITE_EXTERNAL_STORAGE"
          );
          return false; }}return true; ,}}};Copy the code

Image upload

  1. Check: Check whether the file is selected; Whether the file is too large; The file type is correct
  2. Processing: image compression, Base64 conversion
export default {
  methods: {
    uploadImg(e) {
      // Check if any files are selected
      const files = e.target.files || e.dataTransfer.files;
      if(! files.length) {return;
      }

      // Check whether the file is too large
      const file = files[0];
      if (file.size / 1024 > 5000) {
        this.$toast.show("The picture is too big. Please compress it and upload it again.", {
          duration: 3000});return;
      }

      // Determine the type of file: it must be an image
      if (!/^image\//.test(file.type)) {
        this.$toast.show("Please upload a picture", { duration: 3000 });
        // Clear the data if it is not a picture
        document.getElementById("uploadIcon").value = "";
        return;
      }

      this.convertBase64(file, (blob) = > {
        const data = this.compress(blob); // Compress the photo
        console.log('Compressed image size', the data length)const imageData = {
          time: new Date().getTime(),
          uri: data,
        };
        this.$emit("on-upload", imageData); }); ,}}};Copy the code

Preview picture

Image preview: Converts image data to Base64 format and returns it to the user

  1. Filereader. readAsDataURL(file) Gets the string of data:base64. Synchronous execution (immediate)
  2. Url.createobjecturl (blob) Gets an in-memory URL of the current File, representing the specified File object or BLOb object. Asynchronous execution (takes time)
export default {
  methods: {
    convertBase64(file, callback) {
      // Check whether FileReader is supported
      if (!window.FileReader) {
        const URL = window.URL || window.webkitURL;
        const blob = URL.createObjectURL(file); // Get the file stream of the photo
        if (callback) {
          callback(blob);
        }
        return;
      }

      // Create a reader
      const reader = new FileReader();
      // Convert the image to base64 format
      reader.readAsDataURL(file);
      // Callback after successful reading
      reader.onloadend = (e) = > {
        const result = e.target.result;

        // Solve the problem of invalid upload of duplicate image: clear first
        document.getElementById("uploadIcon").value = "";

        // Image processing
        const img = new Image();
        img.src = result;

        console.log("Uncompressed image", result.length);

        img.onload = () = > {
          if(callback) { callback(img); }}; }; ,}}};Copy the code

Image compression

export default {
  methods: {
    compress(img) {
      // Compress proportionally by default
      const width = img.width;
      const height = img.height;
      const scale = width / height;
      / / generated canvas
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");
      canvas.width = this.width || width;
      canvas.height = this.height || width / scale || height;
      / / background
      ctx.fillStyle = "#fff";
      ctx.fillRect(0.0, canvas.width, canvas.height);
      ctx.drawImage(img, 0.0, width, height);

      // The smaller the quality value, the more blurred the image is drawn.
      let quality = 0.1; // The default image quality is 0.1, with minimal compression
      if (this.quality && this.quality <= 1 && this.quality > 0) {
        quality = this.quality;
      }
      const base64 = canvas.toDataURL("image/jpeg", quality);
      returnbase64; ,}}};Copy the code

Turn base64 Blob

Convert base64 image URL data to Blob

export default {
  methods: {
    dataURLtoBlob(dataUrl) {
      const arr = dataUrl.split(",");
      const mime = arr[0].match(/ : (. *?) ; /) [1];
      const bStr = atob(arr[1]);
      let n = bStr.length;
      const u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bStr.charCodeAt(n);
      }
      return new Blob([u8arr], { type: mime }); ,}}};Copy the code