Vue3实现图片上传预览以及拖拽

前言

图片上传使用Ant Design Vue中的upload组件,预览使用Ant Design Vue中的Model组件,拖拽则使用vuedraggable。

介绍

vuedraggable为基于Sortable.js的vue组件,用以实现拖拽功能。
官方地址:https://github.com/SortableJS/Vue.Draggable
中文版文档:https://www.itxst.com/vue-draggable/tutorial.html

安装

npm install vuedraggable -S

使用

import Draggable from ‘vuedraggable’

接下来回到主题,实现功能

代码如下:

// 上传部分
	<Upload
      action="自己的上传地址"
      list-type="picture"
      v-model:fileList="fileList1"
      @change="handleChange"
      @preview="handlePreview"
      class="upload-list-inline"
      accept=".png,.jpg"
      :before-upload="beforeUpload"
      multiple="true"
    >
      <div class="upload">
        <plus-outlined />
        <div class="ant-upload-text">Upload</div>
      </div>
    </Upload>
    
//预览
	<Modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
      <img alt="" style="width: 100%" :src="previewImage" />
    </Modal>
    <div class="tip"> 只支持png/jpg格式,最大支持5M </div>
    
//拖拽
	<draggable :list="fileListArr" @dragend="dragComplete">
      <template #item="{ element }">
        <div class="imgList">
          <a>
            <div class="mask">
              <EyeOutlined class="icon-preview" @click="handlePreview(element.imageUrl)" />
              <DeleteOutlined class="icon-delete" @click="deleteImg(element)" />
            </div>
          </a>
          <img :src="element.imageUrl" alt="" class="img" />
        </div>
      </template>
    </draggable>
// typescript
export default defineComponent({
    name: 'InstructionContentItemTemplateImagesDrawer',
    components: {
      PlusOutlined,
      Upload,
      Modal,
      draggable,
      DeleteOutlined,
      EyeOutlined,
    },
    setup(_, { emit }) {
      const isUpdateView = ref(true);
      const previewVisible = ref<boolean>(false);
      const previewImage = ref<string | undefined>('');
      const fileList = ref<FileItem[]>([]);
      const fileList1 = ref([]);
      const fileListArr = ref<any>([]);
      const recordId = ref('');
      let num = ref();

      const handleCancel = () => {
        previewVisible.value = false;
      };
      
	//点击图片预览
      const handlePreview = async (item) => {
        previewImage.value = item;
        previewVisible.value = true;
      };

	//上传文件状态改变时
      const handleChange = ({ file, fileList }) => {
        if (file.status == 'done') {
          if (fileListArr.value.length >= num.value) {
            fileListArr.value.push({ ...file });
            fileListArr.value[fileListArr.value.length - 1].sort = String(
              fileListArr.value.length - 1,
            );
            fileListArr.value[fileListArr.value.length - 1].instructionContentId = recordId.value;
            //下面的删除是因为接口返回的数据有些不需要,所以删掉,根据实际情况选择,后面涉及到的delete同理;imageUrl,instructionContentId 等属性命名根据实际情况修改
            delete fileListArr.value[fileListArr.value.length - 1].lastModified;
            delete fileListArr.value[fileListArr.value.length - 1].lastModifiedDate;
            delete fileListArr.value[fileListArr.value.length - 1].name;
            delete fileListArr.value[fileListArr.value.length - 1].originFileObj;
            delete fileListArr.value[fileListArr.value.length - 1].percent;
            delete fileListArr.value[fileListArr.value.length - 1].response;
            delete fileListArr.value[fileListArr.value.length - 1].size;
            delete fileListArr.value[fileListArr.value.length - 1].status;
            delete fileListArr.value[fileListArr.value.length - 1].thumbUrl;
            delete fileListArr.value[fileListArr.value.length - 1].type;
            delete fileListArr.value[fileListArr.value.length - 1].uid;
            delete fileListArr.value[fileListArr.value.length - 1].xhr;
          } else {
            for (let i in fileList) {
              fileListArr.value.push({ ...fileList[i] });
              fileListArr.value[i].sort = String(i);
              fileListArr.value[i].imageUrl = fileList[i].response.data.url;
              fileListArr.value[i].instructionContentId = recordId.value;
              delete fileListArr.value[i].lastModified;
              delete fileListArr.value[i].lastModifiedDate;
              delete fileListArr.value[i].name;
              delete fileListArr.value[i].originFileObj;
              delete fileListArr.value[i].percent;
              delete fileListArr.value[i].response;
              delete fileListArr.value[i].size;
              delete fileListArr.value[i].status;
              delete fileListArr.value[i].thumbUrl;
              delete fileListArr.value[i].type;
              delete fileListArr.value[i].uid;
              delete fileListArr.value[i].xhr;
            }
          }
        }
      };

	//拖拽时位置计算
      const dragComplete = (event) => {
        let oldIndex = event.oldIndex; //移动初始位置
        let newIndex = event.newIndex; //运动终止位置
        let diff = Math.abs(newIndex - oldIndex); //插值绝对值
        let index = fileListArr.value[oldIndex];
        if (eval(oldIndex) > eval(newIndex)) {
          for (let i = 0; i < diff; i++) {
            fileListArr.value[oldIndex - i] = fileListArr.value[oldIndex - i - 1];
          }
          fileListArr.value[newIndex] = index;
        } else {
          for (let i = 0; i < diff; i++) {
            fileListArr.value[oldIndex + i] = fileListArr.value[oldIndex + i + 1];
          }
          fileListArr.value[newIndex] = index;
        }
        for (let i = 0; i < fileListArr.value.length; i++) {
          fileListArr.value[i].sort = String(i);
        }
      };

      const deleteImg = (value) => {
          fileListArr.value.findIndex((element) => element.imageUrl === value.imageUrl),
        );
        fileListArr.value.splice(
          fileListArr.value.findIndex((element) => element.imageUrl === value.imageUrl),
          1,
        );
        num.value = num.value - 1;
      };

	//这里使用了代码中封装的组件,以及调用了接口,仅供参考
      const [registerDrawer, { closeDrawer }] = useDrawerInner(async (data) => {
        fileListArr.value = [];
        recordId.value = data.record.id;

        const res = await retrieveInstructionContentAttachmentApi(recordId.value);
        if (res) {
          for (let i = 0; i < res.length; i++) {
            fileListArr.value[i] = { ...res[i] };
            delete fileListArr.value[i].createdAt;
            delete fileListArr.value[i].createdBy;
            delete fileListArr.value[i].delFlag;
            delete fileListArr.value[i].id;
            delete fileListArr.value[i].revision;
            delete fileListArr.value[i].tenantId;
            delete fileListArr.value[i].updatedAt;
            delete fileListArr.value[i].updatedBy;
          }
        }
        num.value = fileListArr.value.length;
      });

      const beforeUpload = (file) => {
        const isLt2M = file.size / 1024 / 1024 < 5;
        if (!isLt2M) {
          message.error('Image must smaller than 5MB!');
        }
        return isLt2M;
      };
      
      return {
        previewVisible,
        previewImage,
        fileList,
        fileList1,
        handleCancel,
        handlePreview,
        handleChange,
        fileListArr,
        dragComplete,
        deleteImg,
        beforeUpload,
      };
    },
  });

// css
.upload {
    width: 120px;
    height: 120px;
    border: 1px rgb(217 217 217) dashed;
    background-color: rgb(250 250 250);
    cursor: pointer;
  }

  .anticon {
    margin: 40px 52px 10px;
    color: #999;
  }

  .ant-upload-text {
    color: #666;
    text-align: center;
  }

  .upload-list-inline :deep(.ant-upload-list-item) {
    width: 120px;
    height: 120px;
    margin-right: 8px;
    padding: 0;
    float: left;
  }

  .upload-list-inline :deep(.ant-upload-animate-enter) {
    animation-name: uploadAnimateInlineIn;
  }

  .upload-list-inline :deep(.ant-upload-animate-leave) {
    animation-name: uploadAnimateInlineOut;
  }

  :deep(.ant-upload-list-item-name) {
    display: none;
  }

  :deep(
      .ant-upload-list-picture .ant-upload-list-item-thumbnail,
      .ant-upload-list-picture-card .ant-upload-list-item-thumbnail
    ) {
    width: 118px;
    height: 118px;
  }

  :deep(
      .ant-upload-list-picture .ant-upload-list-item-thumbnail img,
      .ant-upload-list-picture-card .ant-upload-list-item-thumbnail img
    ) {
    width: 118px;
    height: 118px;
  }

  :deep(
      .ant-upload-list-text .ant-upload-list-item-card-actions,
      .ant-upload-list-picture .ant-upload-list-item-card-actions
    ) {
    margin-left: -30px;
  }

  .tip {
    margin-top: 10px;
    margin-bottom: 20px;
  }

  .imgList {
    position: relative;
    float: left;
  }

  .mask {
    position: absolute;
    top: 0;
    left: 0;
    width: 120px;
    height: 120px;
    margin-top: 15px;
    margin-right: 10px;
    opacity: 0;
    background: rgb(101 101 101 / 60%);
    color: #fff;
  }

  .imgList a:hover .mask {
    opacity: 1;
  }

  .icon-delete {
    position: absolute;
    margin-top: 55px;
    margin-left: 65px;
    color: white;
    cursor: pointer;
  }

  .icon-preview {
    position: absolute;
    margin-top: 55px;
    margin-left: 40px;
    color: white;
    cursor: pointer;
  }

  .img {
    width: 120px;
    height: 120px;
    margin-top: 15px;
    margin-right: 10px;
  }

  :deep(.ant-upload-list) {
    display: none;
  }
效果

在这里插入图片描述
在这里插入图片描述

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过使用Ant Design Vue的Upload组件和Dragger组件实现图片上传拖拽位置。具体代码示例如下: ``` <template> <div> <a-upload :action="uploadUrl" :before-upload="beforeUpload" :on-success="onSuccess" > <a-icon type="upload" /> Click to Upload </a-upload> <a-dragger :action="uploadUrl" :before-upload="beforeUpload" :on-success="onSuccess" > <p class="ant-upload-drag-icon"> <a-icon type="inbox" /> </p> <p class="ant-upload-text">Click or drag file to this area to upload</p> <p class="ant-upload-hint">Support for a single or bulk upload.</p> </a-dragger> <img :src="imageUrl" width="200" height="200" style="margin-top: 20px;"> </div> </template> <script> export default { data() { return { imageUrl: '', uploadUrl: 'your-upload-server-url' }; }, methods: { beforeUpload(file) { // 在这里可以对文件进行校验,例如大小、类型等 console.log('before upload', file); }, onSuccess(response, file, fileList) { // 上传成功后的回调函数 console.log('upload success', response, file, fileList); this.imageUrl = URL.createObjectURL(file.raw); } } }; </script> ``` 在这段代码中,我们使用了`a-upload`组件和`a-dragger`组件来展示图片上传的界面。`a-upload`组件可以通过单击上传按钮或者拖拽到上传区域来完成文件上传;`a-dragger`组件则是将上传区域改为了一个拖拽框,视频等其他多格式的文件也能方便的拖拽上传。同时,我们在`beforeUpload`函数中可以对文件进行校验,并在`onSuccess`函数中处理上传成功后的事件。最后设置`imageUrl`的值为上传图片预览链接即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值