Vue元件封裝上傳圖片和視訊的示例程式碼
阿新 • • 發佈:2021-08-02
首先下載依賴:
cnpm i -S -uuid ali-oss
圖片和視訊欄位都是陣列型別,保證可以上傳多個檔案。
UploadImageVideo:
<!--UploadImageVideo 分片上傳 --> <template>gUpLOk <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">選擇檔案</el-button> <div slot="tip" clgUpLOkass="el-upload__tip">{{ tip }}</div> </el-upload> <el-dialog title="上傳進度" :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,//儲存位置 bucket: { type: String,required: true },currentUrls: { type: Array,default: () => [],//限制上傳檔案數量 limitFileNumber: { type: Number,default: 1 },//是否支援多選 isMultiple: { type: Boolean,default: false },//檔案格式 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: { //注意:計算屬性裡面慎用console.log()來列印,因為有可能列印的變數是依賴某個屬性而出現該計算屬性重複呼叫!!!!!! _fileList() { const arr = []; //一定要this.currentUrls判斷一下是否非空,否則要報錯 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; //這行程式碼很重要!! return arr; } },created() {},mounted() {},methods: { handleChange(file,fileList) { this.fileList = fileList; },handleRemove(file,handleExceed(files,fileList) { this.$message.warning( `當前限制選擇 ${this.limitFileNumber} 個檔案,本次選擇了 ${ files.length } 個檔案,共選擇了 ${files.length + fileList.length} 個檔案` ); },//注意:為了讓自定義上傳handleHttpRequest生效,需滿足: // 1、設定:auto-upload='true'或者不寫這個屬性,因為它預設為true 2、設定action='#'或者直接寫action handleHttpRequest(file) { //雖然沒有內容,但是這個函式不能少! },//注意:自定義上傳handleHttpRequest必須要生效,才會觸發before-upload鉤子函式 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("上傳圖片只能是 JPEG/JPG/PNG 格式!"); return false; } if (!isLt5M) { this.$message.error("單張圖片大小不能超過 5MB!"); return false; } } if (this.fileType == "video") { let { type,name } = file; let isMP4 = type === "video/mp4"; let isLt50M = size / 1024 / 1024 < 50; if (!isMP4) { this.$message.error("上傳視訊只能是 MP4 格式!"); return false; } if (!isLt50M) { this.$message.error("單個視訊大小不能超過 50MB!"); return false; } } },// 分片上傳資料,可展示進度條。上傳重新命名後的檔案到alioss,並返回單個檔案url字串。可支援中文檔名 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); },//批量上傳檔案。返回成功上傳的url陣列 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; },//更新檔案資料。上傳新資料到伺服器,並刪除伺服器中的舊資料,返回更新後的url陣列 async UpdateFiles() { let arr_newUploaded = []; //新上傳的圖片url。 let arr_original = []; //原有的圖片url。不用刪除 let arr_delete = []; //需要刪除的圖片url。 if (this.fileList.length !== 0) { for (const { raw,name,url } of this.fileList) { //注意:這裡一定要判斷raw是否存在。存在,則表示是新上傳的;不存在,則表示是原有的 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]; },//批量刪除伺服器中的檔案。引數:待刪除到伺服器檔案url陣列。 async deleteMultiFiles(urls = []) { let arr_pathname = []; if (urls.length !== 0) { for (const item of urls) { //不要用let url=require("url");url.parse();已失效。要用new URL() let { pathname } = new URL(item); // decodeURIComponent()函式將中文亂碼轉為中文 arr_pathname.push(decodeURIComponent(pathname)); } //刪除伺服器中的圖片 await this.client.deleteMulti(arr_pathname); } } },watch: {} }; </script> <style lang="s" scoped> .UploadImageVideo { /*去除upload元件過渡效果*/ ::v-deep .el-upload-list__item { transition: none !important; } } </style>
使用:
<UploadImageVideo ref="ref_UploadImageVideo" bucket="xxx" :currentUrls="formData.imgurl" :limitFileNumber="3" tip="1、最多上傳3張照片; 2、上傳圖片只能是 JPEG/JPG/PNG 格式; 3、單張圖片大小不能超過 5MB!" fileType="image" :isMultiple="true" ></UploadImageVideo>
- fileType可選。預設不寫,表示圖片、視訊都可上傳。fileType="image"表示只能上傳圖片。fileType="video"表示只能上傳視訊
- bucket必選。
- isMultiple可選。預設為false
- currentUrls必選。當前目前已有的檔案伺服器url陣列。通常新增檔案時,傳入的currentUrls為空陣列[];更新檔案時,傳入到currentUrls為非空陣列
- tip可選。提示內容
提供的方法:(當前元件中所有的上傳都是批量上傳,且為分片上傳,以展示上傳進度條)
- UpdateFiles()。更新檔案資料。上傳新資料到伺服器,並刪除伺服器中的舊資料,返回更新後的url陣列
- addFiles()。批量上傳檔案。返回成功上傳的url陣列
- deleteMultiFiles(urls=[])。批量刪除伺服器中的檔案。引數:待刪除到伺服器檔案url陣列。
- UploadImageVideo(filename,file)。分片上傳資料,可展示進度條。上傳重新命名後的檔案到alioss,並返回單個檔案url字串。可支援中文檔名
呼叫元件中的方法:例如可通過 leturls=awaitthis.$refs["ref_UploadImageVideo"].addFiles();呼叫批量上傳圖片或視訊的方法
例1:
<!--userManage--> <template> <div class="userManage"> <el-card> <div style="margin-bottom: 10px"> <el-input v-model="searchName" clearable placeholder="輸入使用者名稱稱搜尋" style="width: 200px; margin-right: 10px" /> <el-button sizi="mini" type="success" icon="el-icon-search" @click="searchUser(searchName)" >搜尋</el-button> <el-button sizi="mini" type="warning" icon="el-icon-refresh-left" @click="searchName = ''" >重置</el-button> <el-button sizi="mini" @click="handleAdd()" type="primary" icon="el-icon-plus">新增</el-button> <el-button @click="getUserList()" sizi="mini" icon="el-icon-refresh" style="float: right">重新整理</el-button> </div> <el-table :data="tableData" border v-loading="isLoading"> <el-table-column label="使用者名稱" prop="username" align="center" width="150px"></el-table-column> <el-table-column label="密碼" prop="password" align="center"></el-table-column> <el-table-column label="圖片" 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="操作" align="center"> <template slot-scope="scope"> <el-button size="mini" @click="showEditDialog(scope.row)"> <i class="el-icon-edit" /> 編輯 </el-button> <el-button size="mini" type="danger" @click="handleDelete(scope.row)"> <i class="el-icon-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."; 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: {},mounted() { this.getUserList(); },computed: {},methods: { //獲取使用者列表 async getUserList() { this.isLoading = true; let { data } = await getUserList(); this.tableData = data.data; this.isLoading = false; },//開啟新增使用者視窗 handleAdd() { this.dialog = { show: true,title: "新增使用者",option: "add" }; this.formData = { username: "",password: "",imgurl: [] }; },//開啟編輯使用者視窗 showEditDialog(row) { this.currentImgs = row.imgurl; this.dialog = { show: true,title: "編輯使用者",option: "edit" }; this.formData = { _id: row._id,username: row.username,password: row.password,imgurl: row.imgurl }; },//新增使用者 async addUser(urls) { this.formData.imgurl = urls; await addUser(this.formData); this.dialog.show = false; this.$notify({ title: "成功",message: "新增使用者成功!",type: "success" }); this.getUserList(); },//編輯使用者 async editUser(urls) { this.formData.imgurl = urls; await editUser(this.formData,this.formData._id); //更新,尤其是圖片url this.dialog.show = false; this.$notify({ title: "成功",message: "編輯使用者成功!",//刪除使用者 handleDelete({ _id }) { this.$confirm("此操作將永久刪除該檔案,是否繼續?","提示",{ confirmButtonText: "確定",cancelButtonText: "取消",type: "warning" }) .then(async () => { this.$message({ type: "success",message: "刪除成功!",showClose: true }); let { data: { imgurl } } = await deleteUser(_id); //刪除伺服器中的檔案。傳入待刪除的url陣列 await deleteMultiFiles(imgurl); this.getUserList(); }) .catch(() => { this.$message({ type: "info",message: "已取消刪除",showClose: true }); }); },//根據使用者名稱查詢 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="使用者名稱" prop="username">
<el-input v-model="formData.username" autocomplete="off" style="width: 90%"></el-input>
</el-form-item>
<el-form-item label="密碼" prop="password">
<el-input v-model="formData.password" autocomplete="off" style="width: 90%"></el-input>
</el-form-item>
<el-form-item label="圖片" prop="imgurl">
<!-- fileType屬性不寫的話,表示圖片、視訊都可上傳。fileType="image"表示只能上傳圖片。fileType="video"表示只能上傳視訊 -->
<UploadImageVideo
ref="ref_UploadImageVideo"
bucket="bucket-lijiang-test"
:currentUrls="formData.imgurl"
:limitFileNumber="3"
tip="1、最多上傳3張照片; 2、上傳圖片只能是 JPEG/JPG/PNG 格式; 3、單張圖片大小不能超過 5MB!"
fileType="image"
:isMultiple="true"
></UploadImageVideo>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialog.show = false">取 消</el-button>
<el-button
v-if="dialog.option == 'add'"
@click="addUser('ref_form_userManage')"
type="primary"
>確 定</el-button>
<el-button
v-if="dialog.option == 'edit'"
@click="editUser('ref_form_userManage')"
type="primary"
>確 定</el-button>
</dwww.cppcns.comiv>
</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: "請輸入使用者名稱稱",trigger: "blur" }
]
}
};
},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; //刪除檔案陣列 export async function deleteMultiFiles(urls = []) { let arr_pathname = []; if (urls.length !== 0) { for (const item of urls) { //不要用let url=require("url");url.parse();已失效。要用new URL() let { pathname } = new URL(item); // decodeURIComponent()函式將中文亂碼轉為中文 arr_pathname.push(decodeURIComponent(pathname)); } await client.deleteMulti(arr_pathname); } }
import request from '@/utils/request'
// 獲取使用者列表
export functigUpLOkon getUserList() {
return request({
url: '/api/userManage',method: 'get'
})
www.cppcns.com}
// 新增使用者
export function addUser(data) {
return request({
url: '/api/userManage',method: 'post',data
})
}
// 編輯使用者
export function editUser(data,_id) {
return request({
url: `/api/userManage/${_id}`,method: 'put',data
})
}
// 刪除使用者
export function deleteUser(_id) {
return request({
url: `/api/userManage/${_id}`,method: 'delete'
})
}
// 根據關鍵字查詢
export function searchUser(data) {
return request({
url: `/api/userManage/search`,method: 'get',params: data
})
}
const router = require('koa-router')() const User = require("../models/User"); //引入模組模型 router.prefix('/userManage') //獲取使用者列表 router.get('/',async (ctx,next) => { let data = await User.find({}) ctx.body = { code: 200,message: "請求成功",data,} }) //新增使用者 router.post('/',next) => { let { username,password,imgurl } = ctx.request.body; await User.create({ username,imgurl }) ctx.body = { code: 200,message: "新增成功" } }) //編輯使用者 router.put('/:_id',imgurl } = ctx.request.body; let { _id } = ctx.params await User.findByIdAndUpdate(_id,{ username,message: "編輯成功" } }) //刪除使用者 router.delete('/:_id',next) => { let { _id } = ctx.params; let { imgurl } = await User.findByIdAndDelete(_id) ctx.body = { code: 200,message: "刪除成功",imgurl } }) //根據關鍵字查詢使用者。模糊查詢 router.get('/search',next) => { let { searchName } = ctx.request.query; let data = await User.find({ username: { $regex: searchName } }) ctx.body = { code: 200,message: "查詢成功",data } }) module.exports = router
到此這篇關於Vue封裝上傳圖片和視訊的元件的文章就介紹到這了,更多相關vue元件封裝內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!