这里创建项目就不多说了
安装element-plus
安装vuedraggable
安装ali-oss
这里是封装一下:在components创建文件夹jc-upload>jc-upload.vue
在封装的过程中碰到了一个问题就是draggable和el-upload上传按钮独占一行,显然不是我们需要的效果,先看问题
百度了一下,没有找到什么办理办法,这里通过一行css办理以上问题,如有大佬有更好的方案可以分享一下
- .draggable-container {
- display: contents;
- }
复制代码 完整代码
- <template>
- <div class="upload-container">
- <draggable class="draggable-container" v-model="newsFileList" itemKey="url" ghost-class="ghost" animation="300">
- <template #item="{ element }">
- <ul class="el-upload-list el-upload-list--picture-card">
- <li :key="element.url" class="el-upload-list__item is-success animated">
- <img class="el-upload-list__item-thumbnail" :src="element.url" alt="">
- <label class="el-upload-list__item-status-label">
- <i class="el-icon el-icon--upload-success el-icon--check">
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
- <path fill="currentColor"
- d="M406.656 706.944 195.84 496.256a32 32 0 1 0-45.248 45.248l256 256 512-512a32 32 0 0 0-45.248-45.248L406.592 706.944z">
- </path>
- </svg>
- </i>
- </label>
- <i class="el-icon-close"></i>
- <span class="el-upload-list__item-actions">
- <!-- 预览 -->
- <span class="el-upload-list__item-preview"
- @click="handlePictureCardPreview(element)">
- <i class="el-icon el-icon--zoom-in">
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
- <path fill="currentColor"
- d="m795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704zm-32-384v-96a32 32 0 0 1 64 0v96h96a32 32 0 0 1 0 64h-96v96a32 32 0 0 1-64 0v-96h-96a32 32 0 0 1 0-64h96z">
- </path>
- </svg>
- </i>
- </span>
- <!-- 删除 -->
- <span class="el-upload-list__item-delete" @click="handleRemove(element)">
- <i class="el-icon el-icon--zoom-in">
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
- <path fill="currentColor"
- d="M160 256H96a32 32 0 0 1 0-64h256V95.936a32 32 0 0 1 32-32h256a32 32 0 0 1 32 32V192h256a32 32 0 1 1 0 64h-64v672a32 32 0 0 1-32 32H192a32 32 0 0 1-32-32V256zm448-64v-64H416v64h192zM224 896h576V256H224v640zm192-128a32 32 0 0 1-32-32V416a32 32 0 0 1 64 0v320a32 32 0 0 1-32 32zm192 0a32 32 0 0 1-32-32V416a32 32 0 0 1 64 0v320a32 32 0 0 1-32 32z">
- </path>
- </svg>
- </i>
- </span>
- </span>
- </li>
- </ul>
- </template>
- </draggable>
- <el-upload
- ref="uploadRef"
- :show-file-list="false"
- :class="newsFileList.length >= limit ? 'upload-hide' : ''"
- :action="action"
- :accept="accept"
- list-type="picture-card"
- :file-list="newsFileList"
- :on-remove="handleRemove"
- :on-success="onSuccess"
- :limit="limit"
- :disabled="disabled"
- with-credentials
- :multiple="limit > 1? true : false"
- drag>
- <el-icon><Plus /></el-icon>
- </el-upload>
- <el-dialog v-model="dialogVisible">
- <img class="uy-w-p-100" w-full :src="dialogImageUrl" alt="Preview Image" />
- </el-dialog>
- </div>
- </template>
- <script lang="ts" setup>
- import { reactive, ref, watch } from 'vue'
- import { ElNotification, type UploadFile } from 'element-plus'
- import OSS from 'ali-oss';
- import draggable from 'vuedraggable';
- const $emit = defineEmits(['success'])
- /**
- * 组件props
- */
- const props = defineProps({
- action: {
- type: String,
- // default: `${import.meta.env.VITE_SERVE}/api/Osstoken/getToken`
- default: `/api/api/Osstoken/getToken`
- },
- fileList: {
- type: Array as () => UploadFile[],
- default: () => []
- },
- limit: {
- type: Number,
- default: 1
- },
- accept: {
- type: String,
- default: 'image/*'
- },
- disabled: {
- type: Boolean,
- default: false
- }
- })
- // data数据
- const uploadRef = ref()
- const dialogImageUrl = ref('')
- const dialogVisible = ref(false)
- const disabled = ref(false)
- let newsFileList = ref(props.fileList);
- // methods方法
- const handleRemove = (file: UploadFile) => {
- const index = newsFileList.value.findIndex(item => item.url === file.url);
- newsFileList.value.splice(index, 1);
- $emit('success', newsFileList)
- };
- const handlePictureCardPreview = (file: UploadFile) => {
- dialogImageUrl.value = file.url!
- dialogVisible.value = true
- };
- const uploadAliyun = async (res: any, file: UploadFile, fileList: UploadFile[]) => {
- if (res.code === 0) {
- let date = new Date();
- let year = date.getFullYear();
- let month = date.getMonth() + 1;
- let day = date.getDate();
- let formattedMonth = month.toString().padStart(2, '0');
- let formattedDay = day.toString().padStart(2, '0');
- const filePath = `/uploads/${year}/${formattedMonth}/${formattedDay}/${Date.parse(date.toString()) + parseInt((Math.random() * (100000 - 10000 + 1) + 10000).toString(), 10).toString()}.${file.raw?.name.split('.').pop()}`
- let client = new OSS({
- accessKeyId: res.data.AccessKeyId, //OSS的用户名
- accessKeySecret: res.data.AccessKeySecret, //OSS密钥
- region: res.data.region, //域名是创建Buckiet,时选择的服务器地址 比如选择 华南3(广州):oss-cn-guangzhou
- bucket: res.data.bucket, //创建Buckiet的名称
- stsToken: res.data.SecurityToken //临时Token
- })
- const put = async () => {
- try {
- const result = await client.put(filePath, file.raw!);
- if(result.res.status === 200) {
- if(props.accept === 'video/*') {
- file.url = (result.res as any).requestUrls[0] + '?x-oss-process=video/snapshot,t_0,f_jpg';
- }
- newsFileList.value.push({
- url: (result.res as any).requestUrls[0],
- name: '',
- status: 'success',
- uid: 0
- })
- $emit('success', newsFileList)
- }
- } catch (err) {
- ElNotification.success({ message: '上传失败~' });
- }
- }
- put();
- } else {
- ElNotification.success({ message: res.msg });
- }
- };
- const onSuccess = (res: any, file: UploadFile, fileList: UploadFile[]) => {
- uploadAliyun(res, file, fileList)
- };
- watch(() => props.fileList, (newVal) => {
- newsFileList.value = newVal
- }, { deep: true })
- watch(() => newsFileList.value, (newVal) => {
- if(JSON.stringify(newVal) !== JSON.stringify(props.fileList)) {
- $emit('success', newVal)
- }
- }, { deep: true })
- </script>
- <style lang="scss" scoped>
- :deep(.el-upload-dragger) {
- padding: 56px 0;
- background-color: transparent;
- border: none;
- }
- .upload-hide {
- position: relative;
- :deep(.el-upload--picture-card) {
- display: none;
- }
- }
- .upload-container {
- display: flex;
- flex-wrap: wrap;
- .draggable-container {
- display: contents;
- }
- }
- </style>
复制代码
对以上代码解释一下
重点办理el-upload上传按钮独占一行问题
- .upload-container {
- display: flex;
- flex-wrap: wrap;
- .draggable-container {
- display: contents;
- }
- }
复制代码 主要对limit最大限制对上传按钮隐藏
- .upload-hide {
- position: relative;
- :deep(.el-upload--picture-card) {
- display: none;
- }
- }
复制代码 action主要获取OSS上传凭证这里用了代理,通过前端请求后端接口会拒绝访问,线上不需要代理
这段代码主要为了更新排序后的数组
- watch(() => newsFileList.value, (newVal) => {
- if(JSON.stringify(newVal) !== JSON.stringify(props.fileList)) {
- $emit('success', newVal)
- }
- }, { deep: true })
复制代码 这里为什么选用ref并不是为了省事ref一把梭,刚开始我用的 reactive但是在排序的时候一直回弹,详细缘故原由没有深究,换成ref就没问题了
- let newsFileList = ref(props.fileList);
复制代码 就解释这么多吧,有什么疑问或不明白的地方可以留言,有什么更好的方案请大佬们见教,写的不好请多多担待
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |