DOM元素
<template>
<div class="upload">
<div class="mediabox" v-for="(media, index) in mediaList" :key="media.id">
<img v-if="media.type === 'image'" :class="setMediaStyle(media)" :src="media.url" alt="uploaded image" @dblclick="media.showdelBtn = true" />
<video v-else :src="media.url" :class="setMediaStyle(media, index)" controls @dblclick="media.showdelBtn = true"></video>
<button v-if="media.showdelBtn" @click="media.showdelBtn = false">
<el-icon @click="deleteMedia(media.id)" color="#fff" size="40"><Delete /></el-icon>
</button>
</div>
<label for="file-upload" v-if="maxMediaCount != mediaList.length" class="upload-btn">
<el-icon size="30" color="#888"><Plus /></el-icon>
</label>
<input id="file-upload" type="file" accept="image/*, video/*" @change="handleFileChange" />
</div>
</template>
script元素
<script lang="ts" setup >
import { ref } from 'vue';
const mediaList = ref([]);
const maxMediaCount = ref(9); //最大数量
const showaddFile = ref(true);
const handleFileChange = (event) => {
if (mediaList.value.length === maxMediaCount.value) {
showaddFile.value = false;
}
const files = event.target.files;
if (mediaList.value.length + files.length > maxMediaCount.value) {
alert(`最多只能上传 ${maxMediaCount.value} 个素材`);
return;
}
for (let i = 0; i < files.length; i++) {
const file = files[i];
const reader = new FileReader();
reader.onload = () => {
const media = {
id: Date.now(),
type: file.type.includes('image') ? 'image' : 'video',
url: reader.result,
showdelBtn: false,
};
mediaList.value.push(media);
};
reader.readAsDataURL(file);
}
};
const deleteMedia = (id) => {
const index = mediaList.value.findIndex((media) => media.id === id);
if (index !== -1) {
mediaList.value.splice(index, 1);
}
};
const setMediaStyle = (media, i) => {
if (media.type == 'image') {
const img = new Image();
img.src = media.url;
img.onload = () => {
media.width = img.width;
media.height = img.height;
};
}
return media.width > media.height ? 'bigwidth' : 'bigheight';
};
</script>
CSS代码
<style scoped lang="scss">
.upload {
display: flex;
width: 600px !important;
height: 600px;
flex-wrap: wrap;
align-content: flex-start;
.mediabox {
position: relative;
width: 29%;
height: 29%;
background-color: #000;
display: flex;
align-items: center;
justify-content: center;
margin-right: 1%;
margin-bottom: 1%;
overflow: hidden;
.img {
width: 100%;
height: 100%;
}
.video {
width: 100%;
height: 100%;
}
.bigwidth {
width: 100% !important;
height: auto !important;
}
.bigheight {
height: 100% !important;
width: auto !important;
}
button {
position: absolute;
left: 0;
width: 100%;
height: 100%;
border: none;
background-color: rgba($color: #000000, $alpha: 0.5);
}
}
.upload-btn {
width: 29%;
height: 29%;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
margin-right: 1%;
padding: 10px 20px;
border: 3px dashed #888;
border-radius: 10px;
cursor: pointer;
border-radius: 4px;
}
.upload-btn span {
vertical-align: middle;
}
}
#file-upload {
display: none;
}
.media-item {
margin-top: 10px;
}
.media-item button {
margin-top: 5px;
}
</style>
效果图