在 UniApp 开发中,视频上传是高频需求,而将视频直接上传至阿里云 OSS 能有效降低服务器压力、提升上传速度,本文将实现一套 ** 全端兼容(微信小程序 / APP/H5)** 的 UniApp 视频上传方案,包含视频选择、本地预览、OSS 直传、上传状态管理等核心功能,代码可直接复用。
一、前期准备工作
1 安装插件
- 下载插件地址:https://download.csdn.net/download/weixin_44590591/91835674
- 插件会导入至项目的
js_sdk/jason-alioss-upload/目录下,修改配置文件oss.js。
javascript
// 下面这3个信息必填
const url = 'https://xxx.oss-cn-beijing.aliyuncs.com/'
const OSSAccessKeyId = ''
const OssAccesskeySercet= '';
2 阿里云 OSS 配置
- 拥有阿里云 OSS 存储空间,确保存储空间的跨域规则 配置正确(关键,解决 H5 / 小程序跨域问题):
- 允许来源:
*(测试环境,生产环境可配置具体域名) - 允许方法:
GET、POST、PUT、DELETE - 允许头:
* - 暴露头:
ETag - 过期时间:
3600
- 允许来源:
- 获取 OSS 上传所需的密钥信息 (由后端提供,前端禁止硬编码 AccessKey ID/Secret,防止泄露):
- bucket 名称
- OSS 地域节点(如
oss-cn-hangzhou.aliyuncs.com) - 后端签名接口(前端通过接口获取临时上传签名,而非直接使用永久密钥)
插件基础配置(可选)
若需统一配置 OSS 基础信息,可在 oss.js 中简单配置,或在调用上传方法时传入(推荐后端动态返回,更安全)。
二、完整实现代码
本次实现包含视频选择、本地预览、删除已选视频、OSS 直传、上传加载 / 失败提示等完整功能,适配全端,代码结构清晰,可直接集成到项目中。
1 模板部分(template)
html
<template>
<!-- 视频上传容器 -->
<view class="video-upload-container">
<view class="video-upload-input d-flex-cen1 nborder" style="flex-wrap: wrap;">
<!-- 已选视频预览 -->
<view class="iconfont-img video-preview" v-if="form.videoUrl">
<!-- 视频预览(UniApp 全端兼容的视频标签) -->
<video :src="form.videoUrl" mode="aspectFill" controls></video>
<!-- 删除视频按钮 -->
<view class="iconfont icon-shanchu3 video-delete" @tap="deleteVideo"></view>
</view>
<!-- 选择视频按钮(未选视频时显示) -->
<view class="iconfont-img d-flex-cen2 video-add" @tap="addVideo" v-else>
<view class="iconfont icon-dizhi-tianjia video-add-icon"></view>
<text class="video-add-text">点击选择/拍摄视频</text>
</view>
</view>
</view>
</template>
<script>
// 引入 OSS 上传核心方法
import { ossUpload } from "@/js_sdk/jason-alioss-upload/oss.js";
export default {
name: "VideoOssUpload",
data() {
return {
// 表单数据,存储视频 OSS 地址
form: {
videoUrl: ""
}
};
},
methods: {
/**
* 选择/拍摄视频并上传至 OSS
*/
async addVideo() {
const that = this;
// 调用 UniApp 原生视频选择API,全端兼容
uni.chooseVideo({
sourceType: ["camera", "album"], // 支持相机拍摄、相册选择
compressed: false, // 不压缩视频(如需压缩可设为true,根据业务需求调整)
camera: "back", // 默认使用后置摄像头
maxDuration: 60, // 视频最大时长,单位秒(可根据业务自定义)
success: async (res) => {
// 上传前显示加载提示,防止用户重复操作
uni.showLoading({
title: "视频上传中...",
mask: true // 遮罩层,禁止背景操作
});
try {
// 处理视频文件名:截取原文件名,防止特殊字符问题
const pathArr = res.tempFilePath.split("/");
const fileName = pathArr[pathArr.length - 1];
// 拼接完整文件名(保留原后缀,防止OSS识别异常)
const videoName = `${new Date().getTime()}-${fileName}`; // 加时间戳,避免文件名重复
// 调用插件 OSS 上传方法,核心一步
const { success, data } = await ossUpload(
res.tempFilePath, // 视频临时文件路径(uni.chooseVideo 返回)
videoName, // 上传至OSS的文件名
"" // 可选:OSS 文件夹路径,如 "video/2026/",方便OSS文件管理
);
// 上传成功处理
if (success) {
uni.hideLoading();
// 响应式更新视频OSS地址(必须用$set,确保数据双向绑定)
that.$set(that.form, "videoUrl", data);
uni.showToast({
title: "视频上传成功",
icon: "success",
mask: true
});
}
} catch (error) {
// 捕获上传异常
uni.hideLoading();
console.error("视频上传异常:", error);
uni.showToast({
title: "视频上传失败,请重试",
icon: "none",
mask: true
});
}
},
fail: (err) => {
// 选择视频失败处理(如用户取消选择、权限不足)
console.error("选择视频失败:", err.errMsg);
// 排除用户主动取消的情况,避免不必要的提示
if (!err.errMsg.includes("cancel")) {
uni.showToast({
title: "选择视频失败",
icon: "none",
mask: true
});
}
}
});
},
/**
* 删除已选视频
*/
deleteVideo() {
const that = this;
uni.showModal({
title: "提示",
content: "确定要删除该视频吗?",
success: (res) => {
if (res.confirm) {
// 清空视频OSS地址
that.$set(that.form, "videoUrl", "");
}
}
});
}
}
};
</script>
<style lang="scss" scoped>
// 基础布局混合器(复用)
@mixin d-flex-cen {
display: flex;
align-items: center;
justify-content: center;
}
.video-upload-container {
width: 100%;
padding: 20rpx;
box-sizing: border-box;
}
.video-upload-input {
width: 100%;
height: 300rpx;
border: 1px dashed #e5e5e5;
border-radius: 16rpx;
box-sizing: border-box;
padding: 20rpx;
// 视频预览容器
.video-preview {
width: 100%;
height: 100%;
position: relative;
border-radius: 12rpx;
overflow: hidden;
video {
width: 100%;
height: 100%;
object-fit: cover;
}
// 删除按钮
.video-delete {
position: absolute;
top: -10rpx;
right: -10rpx;
width: 40rpx;
height: 40rpx;
background: #ff4444;
color: #fff;
border-radius: 50%;
@include d-flex-cen;
font-size: 24rpx;
z-index: 10;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.2);
}
}
// 选择视频按钮
.video-add {
width: 100%;
height: 100%;
color: #999;
flex-direction: column;
gap: 16rpx;
.video-add-icon {
font-size: 60rpx;
}
.video-add-text {
font-size: 28rpx;
}
&:active {
background: #f5f5f5;
border-radius: 12rpx;
}
}
}
</style>
三、全端兼容注意事项
1 、微信小程序端
- 需在小程序后台配置 OSS 域名白名单:登录微信公众平台 → 开发 → 开发设置 → 服务器域名 → 添加上传 / 下载的 OSS 域名;
- 小程序对临时文件有有效期限制,选择视频后建议立即上传,避免文件失效;
- 相机 / 相册权限:UniApp 会自动向微信小程序申请权限,无需手动配置。
2 、App 端(iOS/Android)
- 需在
manifest.json中配置相机、相册、存储权限 :- iOS:在
ios→plist中添加NSCameraUsageDescription(相机权限说明)、NSPhotoLibraryUsageDescription(相册权限说明); - Android:在
android→permissions中添加CAMERA、READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE;
- iOS:在
- App 端支持大视频上传,建议根据业务需求设置
compressed: true压缩视频,提升上传速度。
3、H5 端
- 确保阿里云 OSS 存储空间跨域规则配置正确(核心,否则会出现跨域报错);
- H5 端对视频文件大小有浏览器限制,建议添加文件大小校验,示例:
javascript
success: async (res) => {
// 校验视频大小,限制500M以内
if (res.size > 500 * 1024 * 1024) {
uni.showToast({ title: "视频大小不能超过500M", icon: "none" });
return;
}
// 后续上传逻辑...
}