First download the dependencies:
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>
Provided methods: (All uploads in the current component are batch uploads and are uploaded in pieces to display the upload progress bar)
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:
|
<<: Detailed explanation of Linux DMA interface knowledge points
>>: Instance method for mysql string concatenation and setting null value
Preface I believe everyone is familiar with addin...
1. Changes in MySQL's default storage engine ...
This article shares two methods of implementing t...
I want to achieve a situation where the width of ...
If we want to make a carousel, we must first unde...
Button is used quite a lot. Here I have sorted ou...
Ubuntu is a free and open source desktop PC opera...
1. Docker cross-host communication Docker cross-h...
0. Overview Zabbix is an extremely powerful ope...
Preface Histogram is a basic statistical informat...
First, let’s take a look at the picture: Today we...
This article example shares the specific code of ...
1. Go to the official website www.mysql.com and s...
I reinstalled the system some time ago, but I did...
This article shares the specific code of js+Html ...