vue3移动端可同时上传照片和视频的组件

uni-app中的uni-file-picker可单独上传照片或视频,但不支持同时上传照片和视频。本篇博客使用image标签和video标签实现移动端(H5+app+小程序)中照片和视频的同时上传。

 本篇博客采用的是照片和视频的单独上传,但可同时展示,支持照片和视频的删除,其中照片和视频均是调用的后端的接口,上传至服务器中,大家可根据个人需要灵活存储照片和视频。

实现效果:

实现代码 :

将照片和视频区分上传,并单独处理,照片采用image标签,视频采用video标签。

<template>
  <!-- 上传视频或者图片 -->
  <view class="up-page">
    <!--图片-->
    <view class="show-box" v-for="(item, index) in imageList" :key="index">
      <image
        class="full"
        :src="item"
        :data-src="image"
        @tap="previewImage(item)"
      >
      </image>
      <view class="delect-icon" @tap="delect(index)">
        <image class="full" :src="clearIcon" mode=""></image>
      </view>
    </view>
    <!--视频-->
    <view class="show-box" v-for="(item1, index1) in videoList" :key="index1">
      <video class="full" :src="item1"></video>
      <view class="delect-icon" @tap="delectVideo(index1)">
        <image class="full" :src="clearIcon" mode=""></image>
      </view>
    </view>
    <view v-if="VideoOfImagesShow" @tap="chooseVideoImage" class="box-mode">
      <image class="full" :src="selectfile" mode=""></image>
    </view>
  </view>
</template>

对照片和视频分别进行上传、删除等操作,避免index值出现错乱,出现错删和误删。 

配置项可进行父组件的传值灵活设置。

此处处理的是将后端上传后的照片或视频id传递出去,此处可根据个人需求灵活设置。但需注意的是,imageList和videoList不要轻易改变,此处是专门使用了对应的id数组进行了重新定义。

<script setup>
import { uploadImg, uploadVideo } from '@/api/upload'

const emit = defineEmits(['getImgUploadIds', 'getVideoUploadIds'])

var sourceType = [['camera'], ['album'], ['camera', 'album']]

const clearIcon = ref(
  'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCAwaDE2YTQgNCAwIDAgMSA0IDR2MTZINGE0IDQgMCAwIDEtNC00VjB6IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXIpIiBmaWxsLW9wYWNpdHk9Ii45OCIgZmlsdGVyPSJ1cmwoI2ZpbHRlcjBfYikiLz48cGF0aCBkPSJNMTAuOTQgOS45OTlsMi44NjMtMi44NTdhLjY2OS42NjkgMCAxIDAtLjk0Ni0uOTQ2TDEwIDkuMDYgNy4xNDMgNi4xOTZhLjY2OS42NjkgMCAwIDAtLjk0Ni45NDZsMi44NjQgMi44NTctMi44NjQgMi44NTdhLjY2Ni42NjYgMCAwIDAgLjIxNyAxLjA5Mi42NjQuNjY0IDAgMCAwIC43MjktLjE0NkwxMCAxMC45MzhsMi44NTcgMi44NjRhLjY2Ny42NjcgMCAwIDAgMS4wOTItLjIxNy42NjYuNjY2IDAgMCAwLS4xNDYtLjcyOUwxMC45MzkgMTB6IiBmaWxsPSIjZmZmIi8+PGRlZnM+PGZpbHRlciBpZD0iZmlsdGVyMF9iIiB4PSItNCIgeT0iLTQiIHdpZHRoPSIyOCIgaGVpZ2h0PSIyOCIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlR2F1c3NpYW5CbHVyIGluPSJCYWNrZ3JvdW5kSW1hZ2UiIHN0ZERldmlhdGlvbj0iMiIvPjxmZUNvbXBvc2l0ZSBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iZWZmZWN0MV9iYWNrZ3JvdW5kQmx1ciIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9ImVmZmVjdDFfYmFja2dyb3VuZEJsdXIiIHJlc3VsdD0ic2hhcGUiLz48L2ZpbHRlcj48bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXIiIHgxPSIyMCIgeDI9IjE1LjU4NiIgeTI9IjIyLjk0IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agc3RvcC1jb2xvcj0iIzBEMUUyOCIgc3RvcC1vcGFjaXR5PSIuOCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzA1MEUxMiIgc3RvcC1vcGFjaXR5PSIuNjUiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4='
)
const selectfile = ref(
  'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIuMjUiIHk9Ii4yNSIgd2lkdGg9IjYzLjUiIGhlaWdodD0iNjMuNSIgcng9IjMuNzUiIGZpbGw9IiNGMkYyRjIiIHN0cm9rZT0iI0YyRjJGMiIgc3Ryb2tlLXdpZHRoPSIuNSIvPjxyZWN0IHg9IjE2IiB5PSIzMSIgd2lkdGg9IjMyIiBoZWlnaHQ9IjIiIHJ4PSIxIiBmaWxsPSIjQkZCRkJGIi8+PHJlY3QgeD0iMzMiIHk9IjE2IiB3aWR0aD0iMzIiIGhlaWdodD0iMiIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKDkwIDMzIDE2KSIgZmlsbD0iI0JGQkZCRiIvPjwvc3ZnPg=='
)
const VideoOfImagesShow = ref(true) // 页面图片或视频数量超出后,拍照按钮隐藏
const imageList = ref([]) //存放图片的地址
const imageListIds = ref([]) //存放图片id的地址
const videoList = ref([]) //视频存放的地址
const videoListIds = ref([]) //存放视频id的地址
// const sourceType = ref(['拍摄', '相册', '拍摄或相册'])
const sourceTypeIndex = ref(2)
const cameraList = ref([
  {
    value: 'back',
    name: '后置摄像头',
    checked: 'true'
  },
  {
    value: 'front',
    name: '前置摄像头'
  }
])
const cameraIndex = ref(0) // 上传视频时的数量
const props = defineProps({
  // 上传配置项
  uploadConfig: {
    type: Object,
    required: true,
    default: () => {
      return {
        //    maxCount: 3,
        //     exParam: 'imgArr'
      }
    }
  },
  imgUrlStr: {
    type: [String, Array],
    required: true,
    default: () => {
      return []
    }
  }
})
// onUnload((val) => {
//   ;(imageList.value = []),
//     (sourceTypeIndex.value = 2),
//     (sourceType.value = ['拍摄', '相册', '拍摄或相册'])
// }),
// 点击上传图片或视频
function chooseVideoImage() {
  uni.showActionSheet({
    title: '选择上传类型',
    itemList: ['图片', '视频'],
    success: (res) => {
      if (res.tapIndex == 0) {
        chooseImages()
      } else {
        chooseVideo()
      }
    }
  })
}
//上传图片
function chooseImages() {
  uni.chooseImage({
    count: props.uploadConfig.maxCount, // 允许选择的数量
    sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
    sourceType: ['album', 'camera'], // 从相册选择
    success: (e) => {
        uni.showLoading({
        mask: true,
        title: '上传中,请稍侯'
      })
      uploadImg(e, props.uploadConfig.exParam).then((res) => {
        const ids = getImgUrl(res)
        imageListIds.value.push(ids)
        emit('getImgUploadIds', imageListIds.value)
        imageList.value = imageList.value.concat(e.tempFilePaths)
        uni.hideLoading()
      })

      if (
        imageList.value.length + videoList.value.length ==
        props.uploadConfig.maxCount
      ) {
        VideoOfImagesShow.value = false //图片上传数量和count一样时,让点击拍照按钮消失
      }
    }
  })
}
//上传视频
function chooseVideo(index) {
  uni.chooseVideo({
    maxDuration: 60, //拍摄视频最长拍摄时间,单位秒。最长支持 60 秒
    count: props.uploadConfig.maxCount,
    camera: cameraList.value[cameraIndex.value].value, //'front'、'back',默认'back'
    sourceType: sourceType[sourceTypeIndex.value],

    success: (e) => {
      uni.showLoading({
        mask: true,
        title: '上传中,请稍侯'
      })
      uploadVideo(e, props.uploadConfig.exParam).then((res) => {
        const ids = getImgUrl(res)
        videoListIds.value.push(ids)
        emit('getVideoUploadIds', videoListIds.value)
        videoList.value = videoList.value.concat(e.tempFilePath)
        uni.hideLoading()
      })
      if (
        imageList.value.length + videoList.value.length ==
        props.uploadConfig.maxCount
      ) {
        VideoOfImagesShow.value = false
      }
    }
  })
}
//预览图片
function previewImage(e) {
  uni.previewImage({
    current: e,
    urls: imageList.value
  })
}
// 删除图片
function delect(index) {
  uni.showModal({
    title: '提示',
    content: '是否要删除该图片',
    success: (res) => {
      if (res.confirm) {
        imageList.value.splice(index, 1)
        imageListIds.value.splice(index, 1)
        emit('getImgUploadIds', imageListIds.value)
      }
      if (
        imageList.value.length + videoList.value.length ==
        props.uploadConfig.maxCount
      ) {
        VideoOfImagesShow.value = false
      } else {
        VideoOfImagesShow.value = true
      }
    }
  })
}
// 删除视频
function delectVideo(index) {
  uni.showModal({
    title: '提示',
    content: '是否要删除此视频',
    success: (res) => {
      if (res.confirm) {
        videoList.value.splice(index, 1)
        videoListIds.value.splice(index, 1)
        emit('getVideoUploadIds', videoListIds.value)
      }
      if (
        imageList.value.length + videoList.value.length ==
        props.uploadConfig.maxCount
      ) {
        VideoOfImagesShow.value = false
      } else {
        VideoOfImagesShow.value = true
      }
    }
  })
}
// 处理图片
function getImgUrl(arr) {
  const idArr = []
  let idStr = ''
  arr.forEach((item) => {
    idArr.push(item.data.id)
  })
  idStr = idArr.join(',')
  return idStr
}
</script>

对视频和照片的尺寸进行定义。可灵活根据个人需求进行设置。

<style lang="scss">
/* 统一上传后显示的盒子宽高比 */
.box-mode {
  width: 20vw;
  height: 20vw;

  border-radius: 8rpx;
  overflow: hidden;
}

.full {
  width: 100%;
  height: 100%;
}

.up-page {
  display: flex;
  flex-wrap: wrap;
  display: flex;
  width: 100%;
  .show-box:nth-child(3n) {
    margin-right: 0;
  }
  .show-box {
    position: relative;
    margin-bottom: 4vw;
    margin-right: 4vw;
    @extend .box-mode;

    .delect-icon {
      height: 40rpx;
      width: 40rpx;
      position: absolute;
      right: 0rpx;
      top: 0rpx;
      z-index: 1000;
    }
  }
}
</style>

以上三部分可组合为一个完整的vue组件,可在父组件中使用。父组件的使用实例

          <FileUpload :uploadConfig="uploadConfig" @getImgUploadIds="uploadImgIds($event)" @getVideoUploadIds="uploadVideoIds($event)"/>

const uploadConfig = ref({
   maxCount: 3,
   exParam: 'imgArr'
})

// 获取图片的ids
function uploadImgIds(val) {
  console.log(val)
}
// 获取视频的ids
function uploadVideoIds(val) {
  console.log(val)
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/899949.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt(简介)

1. Qt简介 Qt是一个基于C的图形用户界面&#xff08;GUI&#xff09;框架&#xff0c;可以开发可视化人机交互程序&#xff0c;但是这并不是Qt的全部。Qt除了可以绘制漂亮的界面外&#xff0c;还包含很多其他的功能&#xff1a;多线程、数据库、图像处理、音视频处理、网络通信…

后台管理员登录实现--系统篇

我的小系统后台原来就有一个上传图片的功能还夹带个删除图片的功能&#xff0c;还嵌到了一个菜单里面。之前效果如下 那么现在为了加大安全力度&#xff0c;想增加一个登录页面。通过登录再到这个页面。看着貌似很简单&#xff0c;但是听我细细说来&#xff0c;要新增些什么东西…

MySQL-视图 (ಥ_ಥ)

文本目录&#xff1a; ❄️一、什么是视图&#xff1a; ❄️二、创建视图&#xff1a; ❄️三、使用视图&#xff1a; ❄️四、修改数据&#xff1a; 1、注意事项&#xff1a; ❄️五、删除视图&#xff1a; ❄️六、视图的优点&#xff1a; ❄️总结&#xff1a; 对于这…

HT7179 26.8V,15A高效升压转换器

1、特征 输入电压范围:2.7V-25V 输出电压范围:最高26.8V 固定开关频率:350kHz 可编程峰值电流:最高15A 高转换效率1 95% (PVIN 12V, VOUT25V, IOUT 2A) 94%(PVIN 12V, VOUT25V, IOUT 4.5A) 93%(PVIN 7.2V, VOUT12V, IOUT 1.5A) 90% (PVIN 7.2V, VOUT12V, IOUT 5A) 96%(PVIN…

Perl打印9x9乘法口诀

本章教程主要介绍如何用Perl打印9x9乘法口诀。 一、程序代码 1、写法① use strict; # 启用严格模式&#xff0c;帮助捕捉变量声明等错误 use warnings; # 启用警告&#xff0c;帮助发现潜在问题# 遍历 1 到 9 的数字 for my $i (1..9) {# 对于每个 $i&#xff0c;遍历 1…

MoCoOp: Mixture of Prompt Learning for Vision Language Models

文章汇总 当前的问题 1)数据集风格变化。 如图1所示&#xff0c;对于一个数据集&#xff0c;单个软提示可能不足以捕获数据中呈现的各种样式。同一数据集中的不同实例可能与不同的提示符兼容。因此&#xff0c;更**自然的做法是使用多个提示来充分表示这些变化**。 2)过拟合…

V4L2驱动框架

文章目录 一、V4L2简介二、v4l2驱动关键组件&#xff08;一&#xff09;video_device结构体v4l2操作方法结构体v4l2的ioctl操作方法结构体 &#xff08;二&#xff09;v4l2_device结构体 一、V4L2简介 V4L2&#xff0c;即Video for Linux two&#xff0c;是Linux内核中用于视频…

qt项目使用其他项目的ui之单继承之成员变量

第一步添加.ui文件 第二步&#xff0c;点击编译(原理&#xff1a;qt的uic会将.ui界面编译成c文件) 第三步&#xff1a;在编译后的目录下找到#include “ui_pagewidget.h” 第四步&#xff1a; #ifndef USA_H #define USA_H#include <QWidget>#include "ui_pagew…

设计模式概览

设计模式是一种解决常见编程问题的经验总结&#xff0c;提供了代码的可重用性、可扩展性和可维护性。常见的设计模式有23个&#xff0c;主要分为三大类&#xff1a;创建型模式、结构型模式和行为型模式。下面是这三类设计模式的详细分类和讲解&#xff1a; 一、创建型模式 创建…

记一个src中危-图像大小与请求参数可修改

记一个src中危-图像大小与请求参数可修改 漏洞描述 服务器生成了一个具有客户端指定尺寸的图像&#xff0c;如果未实施任何限制&#xff0c;则可能导致拒绝服务攻击。 漏洞危害 攻击者不需要在此类攻击中投入资源&#xff0c;但服务器可能会分配所需的像素缓冲区&#xff0…

rk3588_DRM_显示

DRM简介&#xff08;Direct Rendering Manager&#xff09; hdmi 查看hdmir接口状态 cat /sys/class/drm/card0-HDMI-A-2/statusconnected 参考文章 rk3588_dp调试_rk3588 dp接口适配-CSDN博客

十六、【智能体】如何高效利用智能体知识库:打造智能助理的核心支撑

“知识库” 节点可以理解为一个集中存储和管理知识的地方。 就像一个装满各种工具和资源的工具箱&#xff0c;它包含了大量的信息、数据、文档、经验总结等各种知识内容。 为我们提供了一个便捷的途径来获取所需的知识&#xff0c;以解决问题、做出决策或者进行学习和研究。 …

Windows无法打开组策略 | Windows家庭版如何添加和打开组策略

什么是组策略&#xff08;Group Policy&#xff09;&#xff1f; 组策略 是微软Windows操作系统中的一个重要功能&#xff0c;它允许系统管理员通过统一的界面集中配置计算机和用户设置。 组策略设置是通过编辑“组策略对象”&#xff08;GPOs&#xff09;来实现的&#xff0c;…

攻坚金融关键业务系统,OceanBase亮相2024金融科技大会

10月15-16日&#xff0c;第六届中新数字金融应用博览会与2024金融科技大会&#xff08;简称“金博会”&#xff09;在苏州工业园区联合举办。此次大会融合了国家级重要金融科技资源——“中国金融科技大会”&#xff0c;围绕“赋能金融高质量发展&#xff0c;金融科技创新前行”…

Python 学习笔记(十二)—— 网络编程

目录 一、网络编程的基本概念 1.1 IP地址 1.1.1 IP的版本 1.1.2 IP的分类 1.1.2.1 公有地址 1.1.2.2 私有地址 1.1.3 IP地址的范围 1.1.4 回环测试 1.2 常见的网络设备 1.3 端口 1.3.1 端口分配 二、网络通信协议 2.1 常用网络协议 2.2 OSI网络协议七层模型 2.3…

几张图就让你掌握InnoDB 存储引擎底层逻辑架构

前言 &#x1f680; 博主介绍&#xff1a;大家好&#xff0c;我是无休居士&#xff01;一枚任职于一线Top3互联网大厂的Java开发工程师&#xff01; &#x1f680; &#x1f4a1; 无论你是刚刚踏入编程世界的新人&#xff0c;还是希望进一步提升自己的资深开发者&#xff0c;…

10.24.2024刷华为OD C题型(四) -- 对象list按照多个属性排序

文章目录 最长连续子序列AI面板识别语法知识记录 最长连续子序列 https://www.nowcoder.com/discuss/592408743019589632 if __name__ "__main__":# 获取用户输入# numbers int(input().split(,))# str_arr input().split(,)arr [int(num) for num in input(…

【安装教程】使用WSL工具,在Windows11系统上安装Linux模拟环境(逐步教程)

目录 一、为什么要学习Linux系统 二、Linux模拟环境&#xff08;WSL&#xff09; WSL的官方文档 1、下载WSL 2、安装Ubuntu 结语 提示&#xff1a;WSL下的Linux模拟环境是纯命令行操作的。如果想要使用桌面系统&#xff0c;则应该考虑其他的虚拟机&#xff0c;如VMware。我…

从校园到职场:Java实习生面试常见问题

Java实习生面试通常会涵盖多个方面的知识&#xff0c;包括基础知识、项目经验、解决问题的能力以及面试技巧。以下是一些常见的Java实习生面试题及其回答技巧&#xff1a; Java基础知识 问题&#xff1a;Java有那些基本数据类型&#xff0c;String是不是基本数据类型&#xff…

java实现redis的消息发送和消费,类似kafka功能

确保在 pom.xml 中添加了 Spring Data Redis 和 Jedis 的依赖。如下所示&#xff1a;<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency&g…