Vue component encapsulates sample code for uploading pictures and videos

Vue component encapsulates sample code for uploading pictures and videos

First download the dependencies:

cnpm i -S vue-uuid ali-oss

The image and video fields are both array types, ensuring that multiple files can be uploaded.

UploadImageVideo:

<!--UploadImageVideo upload in pieces-->
<template>
  <div class="UploadImageVideo">
    <el-upload
      action
      :on-change="handleChange"
      :on-remove="handleRemove"
      :limit="limitFileNumber"
      :on-exceed="handleExceed"
      :file-list="_fileList"
      :http-request="handleHttpRequest"
      :before-upload="handleBeforeUpload"
      :multiple="isMultiple"
    >
      <el-button slot="trigger" size="small" type="primary">Select file</el-button>
      <div slot="tip" class="el-upload__tip">{{ tip }}</div>
    </el-upload>
 
    <el-dialog
      title="Upload progress"
      :visible.sync="dialogTableVisible"
      :close-on-click-modal="false"
      :modal-append-to-body="false"
    >
      <el-progress :text-inside="true" :stroke-width="26" :percentage="percentage"></el-progress>
    </el-dialog>
  </div>
</template>
 
<script>
import { uuid } from "vue-uuid";
const OSS = require("ali-oss");
 
export default {
  name: "",
  components: {},
  props: {
    region:
      type: String,
      default: "oss-cn-chengdu"
    },
    accessKeyId: {
      type: String,
      default: "xxx"
    },
    accessKeySecret: {
      type: String,
      default: "xxx"
    },
    //Storage location bucket: {
      type: String,
      required: true
    },
    currentUrls: {
      type: Array,
      default: () => [],
      required: true
    },
    //Limit the number of uploaded files limitFileNumber: {
      type: Number,
      default: 1
    },
    //Whether to support multiple selection isMultiple: {
      type: Boolean,
      default: false
    },
    //File format fileType: {
      type: String,
      default: ""
    },
    //tip: {
      type: String
    }
  },
  data() {
    return {
      client: new OSS({
        region: this.region,
        accessKeyId: this.accessKeyId,
        accessKeySecret: this.accessKeySecret,
        bucket: this.bucket
      }),
      percentage: 0,
      dialogTableVisible: false,
      fileList: []
    };
  },
  computed: {
    //Note: Be careful when using console.log() to print in calculated properties, because it is possible that the printed variable depends on a certain property and the calculated property is called repeatedly! ! ! ! ! !
    _fileList() {
      const arr = [];
      // Make sure this.currentUrls is not empty, otherwise an error will be reported if (this.currentUrls.length !== 0) {
        for (const item of this.currentUrls) {
          let { pathname } = new URL(item);
          arr.push({ name: decodeURIComponent(pathname), url: item });
        }
      }
 
      this.fileList = arr; //This line of code is very important! !
      return arr;
    }
  },
  created() {},
  mounted() {},
  methods: {
    handleChange(file, fileList) {
      this.fileList = fileList;
    },
    handleRemove(file, fileList) {
      this.fileList = fileList;
    },
    handleExceed(files, fileList) {
      this.$message.warning(
        `Currently limit selection to ${this.limitFileNumber} files, this time selected ${
          files.length
        } files, ${files.length + fileList.length} files selected`
      );
    },
 
    //Note: In order for the custom upload handleHttpRequest to take effect, the following conditions must be met:
    // 1. Set: auto-upload='true' or do not write this attribute, because it defaults to true 2. Set action='#' or write action directly
    handleHttpRequest(file) {
      //Although there is no content, this function is indispensable!
    },
    //Note: The custom upload handleHttpRequest must be effective to trigger the before-upload hook function handleBeforeUpload(file) {
      if (this.fileType == "image") {
        let { type, size, name } = file;
        let isJPEG = type === "image/jpeg";
        let isJPG = type === "image/jpg";
        let isPNG = type === "image/png";
        let isLt5M = size / 1024 / 1024 < 5;
        if (!isJPEG && !isJPG && !isPNG) {
          this.$message.error("Uploaded images can only be in JPEG/JPG/PNG format!");
          return false;
        }
        if (!isLt5M) {
          this.$message.error("The size of a single image cannot exceed 5MB!");
          return false;
        }
      }
      if (this.fileType == "video") {
        let { type, size, name } = file;
        let isMP4 = type === "video/mp4";
        let isLt50M = size / 1024 / 1024 < 50;
        if (!isMP4) {
          this.$message.error("Uploaded videos can only be in MP4 format!");
          return false;
        }
        if (!isLt50M) {
          this.$message.error("The size of a single video cannot exceed 50MB!");
          return false;
        }
      }
    },
    // Upload data in pieces and display a progress bar. Upload the renamed file to alioss and return a single file url string. Supports Chinese file names async UploadImageVideo(filename, file) {
      let newFileName =
        filename.split(".")[0] + "-" + uuid.v1() + "." + filename.split(".")[1];
      let that = this;
      that.dialogTableVisible = true;
 
      let {
        res: { requestUrls }
      } = await this.client.multipartUpload(newFileName, file, {
        progress: function(p, checkpoint) {
          that.percentage = parseFloat((p * 100).toFixed(2));
        }
      });
      if (that.percentage == 100) {
        that.dialogTableVisible = false;
      }
      let { origin, pathname } = new URL(requestUrls[0]);
      return origin + decodeURIComponent(pathname);
    },
    //Batch upload files. Returns an array of successfully uploaded urls async addFiles() {
      let urls = [];
      if (this.fileList.length !== 0) {
        for (const item of this.fileList) {
          let { name, raw } = item;
          let pathname = await this.UploadImageVideo(name, raw);
          urls.push(pathname);
        }
      }
      return urls;
    },
    //Update file data. Upload new data to the server, delete old data in the server, and return the updated url array async UpdateFiles() {
      let arr_newUploaded = []; //Newly uploaded image url.
      let arr_original = []; //Original image url. No need to delete let arr_delete = []; //The URL of the image to be deleted.
      if (this.fileList.length !== 0) {
        for (const { raw, name, url } of this.fileList) {
          //Note: It is important to determine whether raw exists here. If it exists, it means it is newly uploaded; if it does not exist, it means it is the original if (raw) {
            let pathname = await this.UploadImageVideo(name, raw);
            arr_newUploaded.push(pathname);
          }
          if (this.currentUrls.includes(url)) {
            arr_original.push(url);
          }
        }
      }
 
      for (const element of this.currentUrls) {
        if (!arr_original.includes(element)) {
          arr_delete.push(element);
        }
      }
      await this.deleteMultiFiles(arr_delete);
 
      return [...arr_original, ...arr_newUploaded];
    },
    //Batch delete files in the server. Parameters: Array of URLs of files to be deleted from the server.
    async deleteMultiFiles(urls = []) {
      let arr_pathname = [];
      if (urls.length !== 0) {
        for (const item of urls) {
          //Don't use let url=require("url");url.parse(); it is invalid. To use new URL()
          let { pathname } = new URL(item);
          // decodeURIComponent() function converts Chinese garbled characters into Chinese arr_pathname.push(decodeURIComponent(pathname));
        }
        //Delete the pictures in the server await this.client.deleteMulti(arr_pathname);
      }
    }
  },
  watch: {}
};
</script>
 
<style lang="scss" scoped>
.UploadImageVideo {
  /*Remove the upload component transition effect*/
  ::v-deep .el-upload-list__item {
    transition: none !important;
  }
}
</style>

use:

<UploadImageVideo
  ref="ref_UploadImageVideo"
  bucket="xxx"
  :currentUrls="formData.imgurl"
  :limitFileNumber="3"
  tip="1. Upload up to 3 photos; 2. Uploaded pictures can only be in JPEG/JPG/PNG format; 3. The size of a single picture cannot exceed 5MB!"
  fileType="image"
  :isMultiple="true"
></UploadImageVideo>
  • fileType is optional. By default, it is not set, which means that both pictures and videos can be uploaded. fileType="image" means only images can be uploaded. fileType="video" means only videos can be uploaded
  • bucket is required.
  • isMultipleOptional. Defaults to false
  • currentUrls is required. The current array of file server URLs. Usually when adding a file, the currentUrls passed in is an empty array []; when updating a file, the currentUrls passed in is a non-empty array
  • tip is optional. Tips

Provided methods: (All uploads in the current component are batch uploads and are uploaded in pieces to display the upload progress bar)

  1. UpdateFiles(). Update file data. Upload new data to the server, delete old data in the server, and return the updated url array
  2. addFiles(). Upload files in batches. Returns an array of successfully uploaded URLs
  3. deleteMultiFiles(urls = []). Batch delete files from the server. Parameters: Array of URLs of files to be deleted from the server.
  4. UploadImageVideo(filename, file). Upload data in pieces and display a progress bar. Upload the renamed file to alioss and return a single file url string. Support Chinese file names

Call methods in components: For example, you can call methods for batch uploading images or videos through let urls = await this.$refs["ref_UploadImageVideo"].addFiles();

Example 1:

<!--userManage-->
<template>
  <div class="userManage">
    <el-card>
      <div style="margin-bottom: 10px">
        <el-input
          v-model="searchName"
          clearable
          placeholder="Enter user name to search"
          style="width: 200px; margin-right: 10px"
        />
        <el-button
          size="mini"
          type="success"
          icon="el-icon-search"
          @click="searchUser(searchName)"
        >Search</el-button>
        <el-button
          size="mini"
          type="warning"
          icon="el-icon-refresh-left"
          @click="searchName = ''"
        >Reset</el-button>
        <el-button sizi="mini" @click="handleAdd()" type="primary" icon="el-icon-plus">Add</el-button>
        <el-button @click="getUserList()" sizi="mini" icon="el-icon-refresh" style="float: right">Refresh</el-button>
      </div>
      <el-table :data="tableData" border v-loading="isLoading">
        <el-table-column label="username" prop="username" align="center" width="150px"></el-table-column>
        <el-table-column label="password" prop="password" align="center"></el-table-column>
        <el-table-column label="picture" align="center">
          <template slot-scope="scope">
            <div
              style="
                display: flex;
                justify-content: space-around;
                flex-flow: row wrap;
              "
            >
              <el-image
                style="width: 50px; height: 50px"
                v-for="(item, index) in scope.row.imgurl"
                :key="index"
                :src="item"
                :preview-src-list="scope.row.imgurl"
              ></el-image>
              <!-- <a :href="scope.row.imgurl" rel="external nofollow" target="_blank">{{scope.row.imgurl}}</a> -->
            </div>
          </template>
        </el-table-column>
        <el-table-column label="operation" align="center">
          <template slot-scope="scope">
            <el-button size="mini" @click="showEditDialog(scope.row)">
              <i class="el-icon-edit" /> Edit</el-button>
            <el-button size="mini" type="danger" @click="handleDelete(scope.row)">
              <i class="el-icon-delete" /> Delete</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <UserManageDialog :dialog="dialog" :formData="formData" @addUser="addUser" @editUser="editUser"></UserManageDialog>
  </div>
</template>
 
<script>
import UserManageDialog from "./userManageDialog.vue";
import { client_alioss, deleteMultiFiles } from "@/utils/alioss.js";
 
import {
  addUser,
  getUserList,
  editUser,
  deleteUser,
  searchUser
} from "@/api/userManage/index";
export default {
  name: "userManage",
  components: { UserManageDialog },
  data() {
    return {
      searchName: "",
      isLoading: false,
      dialog: {
        show: false,
        title: ""
      },
      formData: {},
      tableData: [
        {
          _id: "",
          username: "admin",
          password: "123",
          imgurl: []
        }
      ],
      currentImgs: []
    };
  },
  props: {},
  created() {},
  mounted() {
    this.getUserList();
  },
  computed: {},
  methods: {
    //Get the user list async getUserList() {
      this.isLoading = true;
      let { data } = await getUserList();
      this.tableData = data.data;
      this.isLoading = false;
    },
 
    //Open the new user window handleAdd() {
      this.dialog = {
        show: true,
        title: "New User",
        option: "add"
      };
      this.formData = {
        username: "",
        password: "",
        imgurl: []
      };
    },
    //Open the edit user window showEditDialog(row) {
      this.currentImgs = row.imgurl;
 
      this.dialog = {
        show: true,
        title: "Edit User",
        option: "edit"
      };
      this.formData = {
        _id: row._id,
        username: row.username,
        password: row.password,
        imgurl: row.imgurl
      };
    },
    //Add new user async addUser(urls) {
      this.formData.imgurl = urls;
 
      await addUser(this.formData);
      this.dialog.show = false;
      this.$notify({
        title: "Success",
        message: "Added user successfully!",
        type: "success"
      });
      this.getUserList();
    },
    //Edit user async editUser(urls) {
      this.formData.imgurl = urls;
 
      await editUser(this.formData, this.formData._id); //Update the database, especially the image url
 
      this.dialog.show = false;
      this.$notify({
        title: "Success",
        message: "Edit user successfully!",
        type: "success"
      });
      this.getUserList();
    },
    //Delete user handleDelete({ _id }) {
      this.$confirm("This operation will permanently delete the file, do you want to continue?", "Prompt", {
        confirmButtonText: "Confirm",
        cancelButtonText: "Cancel",
        type: "warning"
      })
        .then(async () => {
          this.$message({
            type: "success",
            message: "Deleted successfully!",
            showClose: true
          });
          let {
            data: { imgurl }
          } = await deleteUser(_id);
 
          //Delete the file in the server. Pass in the url array to be deleted await deleteMultiFiles(imgurl);
 
          this.getUserList();
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "Deleted",
            showClose: true
          });
        });
    },
    //Query by user name async searchUser(searchName) {
      this.isLoading = true;
      let { data } = await searchUser({
        searchName
      });
      this.tableData = data.data;
      this.isLoading = false;
    }
  },
  watch: {}
};
</script>
 
<style lang="scss" scoped>
.userManage {
}
</style> 

<!--userManageDialog -->
<template>
  <div class="userManageDialog">
    <el-dialog :title="dialog.title" width="45%" :visible.sync="dialog.show" v-if="dialog.show">
      <el-form ref="ref_form_userManage" :model="formData" :rules="rules" label-width="100px">
        <el-form-item label="username" prop="username">
          <el-input v-model="formData.username" autocomplete="off" style="width: 90%"></el-input>
        </el-form-item>
        <el-form-item label="password" prop="password">
          <el-input v-model="formData.password" autocomplete="off" style="width: 90%"></el-input>
        </el-form-item>
        <el-form-item label="picture" prop="imgurl">
          <!-- If the fileType attribute is not written, it means that both pictures and videos can be uploaded. fileType="image" means only images can be uploaded. fileType="video" means you can only upload videos -->
          <UploadImageVideo
            ref="ref_UploadImageVideo"
            bucket="bucket-lijiang-test"
            :currentUrls="formData.imgurl"
            :limitFileNumber="3"
            tip="1. Upload up to 3 photos; 2. Uploaded pictures can only be in JPEG/JPG/PNG format; 3. The size of a single picture cannot exceed 5MB!"
            fileType="image"
            :isMultiple="true"
          ></UploadImageVideo>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialog.show = false">Cancel</el-button>
        <el-button
          v-if="dialog.option == 'add'"
          @click="addUser('ref_form_userManage')"
          type="primary"
        >OK</el-button>
        <el-button
          v-if="dialog.option == 'edit'"
          @click="editUser('ref_form_userManage')"
          type="primary"
        >OK</el-button>
      </div>
    </el-dialog>
  </div>
</template>
 
<script>
import UploadImageVideo from "@/components/UploadImageVideo";
 
export default {
  name: "userManageDialog",
  components: { UploadImageVideo },
  props: ["dialog", "formData"],
  data() {
    return {
      fileList: [],
      rules:
        username: [
          { required: true, message: "Please enter your username", trigger: "blur" }
        ]
      }
    };
  },
  created() {},
  mounted() {},
  computed: {},
  methods: {
    addUser(formName) {
      this.$refs[formName].validate(async valid => {
        if (valid) {
          let urls = await this.$refs["ref_UploadImageVideo"].addFiles();
          this.$emit("addUser", urls);
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    editUser(formName) {
      this.$refs[formName].validate(async valid => {
        if (valid) {
          let urls = await this.$refs["ref_UploadImageVideo"].UpdateFiles();
 
          this.$emit("editUser", urls);
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    }
  },
  watch: {}
};
</script>
<style lang="scss" scoped>
</style> 

import { uuid } from 'vue-uuid';
const OSS = require("ali-oss");
 
let client = new OSS({
    region: "oss-cn-chengdu",
    accessKeyId: "LTAI5tQPHvixV8aakp1vg8Jr",
    accessKeySecret: "xYyToToPe8UFQMdt4hpTUS4PNxzl9S",
    bucket: "bucket-lijiang-test",
 
});
 
export const client_alioss = client;
 
 
//delete file array export async function deleteMultiFiles(urls = []) {
    let arr_pathname = [];
    if (urls.length !== 0) {
        for (const item of urls) {
            //Don't use let url=require("url");url.parse(); it is invalid. To use new URL()
            let { pathname } = new URL(item);
            // decodeURIComponent() function converts Chinese garbled characters into Chinese arr_pathname.push(decodeURIComponent(pathname));
        }
        await client.deleteMulti(arr_pathname);
    }
} 

import request from '@/utils/request'
// Get the user list export function getUserList() {
    return request({
        url: '/api/userManage',
        method: 'get'
    })
}
 
// Add a new user export function addUser(data) {
    return request({
        url: '/api/userManage',
        method: 'post',
        data
    })
}
 
// Edit user export function editUser(data, _id) {
    return request({
        url: `/api/userManage/${_id}`,
        method: 'put',
        data
    })
}
 
// Delete user export function deleteUser(_id) {
    return request({
        url: `/api/userManage/${_id}`,
        method: 'delete'
    })
}
 
// Query by keyword export function searchUser(data) {
    return request({
        url: `/api/userManage/search`,
        method: 'get',
        params: data
    })
} 

const router = require('koa-router')()
 
const User = require("../models/User"); //Introduce module model router.prefix('/userManage')
 
//Get user list router.get('/', async (ctx, next) => {
    let data = await User.find({})
    ctx.body = {
        code: 200,
        message: "Request successful",
        data,
    }
})
//Add new user router.post('/', async (ctx, next) => {
    let { username, password, imgurl } = ctx.request.body;
    await User.create({ username, password, imgurl })
    ctx.body = { code: 200, message: "Added successfully" }
})
//Edit user router.put('/:_id', async (ctx, next) => {
    let { username, password, imgurl } = ctx.request.body;
    let { _id } = ctx.params
 
    await User.findByIdAndUpdate(_id, { username, password, imgurl })
    ctx.body = { code: 200, message: "Edited successfully" }
})
//Delete user router.delete('/:_id', async (ctx, next) => {
    let { _id } = ctx.params;
    let { imgurl } = await User.findByIdAndDelete(_id)
    ctx.body = { code: 200, message: "Deleted successfully", imgurl }
 
})
 
//Query users based on keywords. Fuzzy query router.get('/search', async (ctx, next) => {
    let { searchName } = ctx.request.query;
 
    let data = await User.find({ username: { $regex: searchName } })
    ctx.body = { code: 200, message: "Query successful", data }
})
module.exports = router

This is the end of this article about Vue encapsulation components for uploading pictures and videos. For more relevant vue component encapsulation content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • vue-cropper plug-in realizes the encapsulation of image capture and upload component
  • Vue development package upload file component and usage examples
  • An example of encapsulating an image upload component based on vue-upload-component
  • An example of Vue encapsulating a simple and lightweight file upload component

<<:  Detailed explanation of Linux DMA interface knowledge points

>>:  Instance method for mysql string concatenation and setting null value

Recommend

How to add fields to a large data table in MySQL

Preface I believe everyone is familiar with addin...

Summary of the differences between MySQL storage engines MyISAM and InnoDB

1. Changes in MySQL's default storage engine ...

JavaScript to achieve fancy carousel effect

This article shares two methods of implementing t...

Flex layout realizes left text overflow and omits right text adaptation

I want to achieve a situation where the width of ...

JavaScript Dom implements the principle and example of carousel

If we want to make a carousel, we must first unde...

Summary of Button's four Click response methods

Button is used quite a lot. Here I have sorted ou...

How to install MySQL database on Ubuntu

Ubuntu is a free and open source desktop PC opera...

Implementation of Docker cross-host network (overlay)

1. Docker cross-host communication Docker cross-h...

Using Zabbix to monitor the operation process of Oracle table space

0. Overview Zabbix is ​​an extremely powerful ope...

MySQL solution for creating horizontal histogram

Preface Histogram is a basic statistical informat...

Example code for Html layered box-shadow effect

First, let’s take a look at the picture: Today we...

js implements a simple countdown

This article example shares the specific code of ...

mysql5.7.22 download process diagram

1. Go to the official website www.mysql.com and s...

js+Html to realize table editable operation

This article shares the specific code of js+Html ...