前言
在uniapp开发过程中,有一个个人中心的上传头像的问题,属于是单文件上传,还有一个是用户发布日常动态的问题,可以带有多张图片,属于是多文件上传,如下是我的解决方案,做个记录吧~
后台 启动!!!
业务场景 1 - 上传头像
🗨️该页面完整代码如下:
<template>
<view class="container">
<view class="icon active">基本信息</view>
<view class="avatar_img">
<image class="img" :src="UserAvatarPic" @click="uploadAvatarImg"></image>
</view>
<view class="avatar_form">
<view class="name" @click="changeName">
<view class="left">昵称</view>
<view class="right">
<view class="a">{{ UserAvatarName }}</view>
<image class="img" src="../../static/rm-more.png"></image>
</view>
</view>
<view class="desc" @click="toSignature">
<view class="left">简介</view>
<view class="right">
<image class="img" src="../../static/rm-more.png"></image>
</view>
</view>
<view class="phone">
<view class="left">绑定手机号</view>
<view class="right">
<view class="a">还未绑定手机号</view>
<image class="img" src="../../static/rm-more.png"></image>
</view>
</view>
<view class="id">
<view class="left">用户 ID</view>
<view view="right">{{ UserAvatarId }}</view>
</view>
</view>
</view>
</template>
<script>
import { modifyUserInfoAvatar } from '../../services/AboutUserInfo.js'
import { mapState } from 'vuex'
export default {
computed: {
...mapState('user_info', ['UserAvatarPic', 'UserAvatarName', 'UserAvatarId'])
},
data() {
return {
userId: null,
tempPicUrl: '',
avatarPicUrl: '',
serverUrl: "http://localhost:8080/user/common/upload", // 接口地址
}
},
mounted() {
uni.getStorage({
key: 'userId',
success: (res) => {
console.log(res.data)
this.userId = res.data
}
})
},
methods: {
toSignature() {
uni.navigateTo({
url: "../../subpkg/Signature-define/Signature-define"
})
},
changeName() {
uni.navigateTo({
url: "../../subpkg/change-name/change-name"
})
},
uploadAvatarImg() {
uni.chooseImage({
count: 1,
success: (res) => {
this.tempPicUrl = res.tempFilePaths[0]
console.log(this.tempPicUrl)
uni.uploadFile({
url: this.serverUrl,
filePath: this.tempPicUrl,
name: "file", // 服务器定义的文件字段为 file
header: {
//设置用户访问的token信息
"authentication": uni.getStorageSync('token')
},
success: (res) => {
console.log('上传成功', res)
console.log(res) // 后端返回的 data 是字符串
let data = JSON.parse(res.data)
console.log(data)
this.avatarPicUrl = data.data
this.modifyUserInfoAfterUpload(this.avatarPicUrl, this.userId)
// 上传成功后使用 vuex 保存,但不做持久处理
this.$store.commit('user_info/UpdateUserAvatarPic', this.avatarPicUrl)
},
fail: (error) => {
console.log('上传失败', error)
console.log(this.tempPicUrl)
}
})
}
})
},
async modifyUserInfoAfterUpload(avatarUrl, userId) {
const res = await modifyUserInfoAvatar(avatarUrl, userId)
console.log('调用结果:', res)
}
},
}
</script>
<style lang="scss">
.container {
width: 100vw;
height: 100vh;
.icon {
width: 100%;
text-align: center;
color: #460779;
font-weight: 600;
}
.active {
position: relative;
z-index: 9999;
color: #460779;
font-weight: 800;
&::after {
position: absolute;
z-index: -9999;
content: "";
width: 40rpx;
height: 40rpx;
background-color: rgba(70,7,121,.2);
left: 50%;
top: 90%;
border-radius: 50%;
transform: translate(-50%, -50%);
}
}
.avatar_img {
width: 80%;
height: 350rpx;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
// background-color: red; // 背景板
.img {
width: 200rpx;
height: 200rpx;
border-radius: 50%;
}
}
.avatar_form {
width: 100%;
.name {
width: 90%;
margin: 0 auto;
border-bottom: 1rpx solid #ccc;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding-bottom: 30rpx;
font-size: 35rpx;
align-items: center;
margin-bottom: 30rpx;
.left {}
.right {
display: flex;
align-items: center;
.a {
font-size: 35rpx;
font-weight: 100;
margin-right: 30rpx;
}
.img {
width: 40rpx;
height: 40rpx;
}
}
}
.sex {
width: 90%;
margin: 0 auto;
border-bottom: 1rpx solid #ccc;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding-bottom: 30rpx;
font-size: 35rpx;
align-items: center;
margin-bottom: 30rpx;
.left {}
.right {
display: flex;
align-items: center;
.a {
font-size: 35rpx;
font-weight: 100;
margin-right: 30rpx;
}
.img {
width: 40rpx;
height: 40rpx;
}
}
}
.desc {
width: 90%;
margin: 0 auto;
border-bottom: 1rpx solid #ccc;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding-bottom: 30rpx;
font-size: 35rpx;
align-items: center;
margin-bottom: 30rpx;
.left {}
.right {
display: flex;
align-items: center;
.a {
font-size: 35rpx;
font-weight: 100;
margin-right: 30rpx;
}
.img {
width: 40rpx;
height: 40rpx;
}
}
}
.phone {
width: 90%;
margin: 0 auto;
border-bottom: 1rpx solid #ccc;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding-bottom: 30rpx;
font-size: 35rpx;
align-items: center;
margin-bottom: 30rpx;
.left {}
.right {
display: flex;
align-items: center;
.a {
font-size: 35rpx;
font-weight: 100;
margin-right: 30rpx;
}
.img {
width: 40rpx;
height: 40rpx;
}
}
}
.id {
width: 90%;
margin: 0 auto;
border-bottom: 1rpx solid #ccc;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding-bottom: 30rpx;
font-size: 35rpx;
align-items: center;
margin-bottom: 30rpx;
.left {}
.right {
display: flex;
align-items: center;
.a {
font-size: 35rpx;
font-weight: 100;
margin-right: 30rpx;
}
.img {
width: 40rpx;
height: 40rpx;
}
}
}
}
}
</style>
🗨️核心代码如下:
uploadAvatarImg() {
uni.chooseImage({
count: 1, //上传数量 默认为 9
success: (res) => {
this.tempPicUrl = res.tempFilePaths[0]
console.log(this.tempPicUrl)
uni.uploadFile({
url: this.serverUrl, // 对应后端接口的完整地址
filePath: this.tempPicUrl, // 图片的临时路径
name: "file", // 服务器定义的文件字段为 file
header: { // 配置请求头信息 => jwt 校验
//设置用户访问的token信息
"authentication": uni.getStorageSync('token')
},
success: (res) => {
console.log('上传成功', res)
console.log(res) // 后端返回的 data 是字符串
let data = JSON.parse(res.data)
console.log(data)
this.avatarPicUrl = data.data
this.modifyUserInfoAfterUpload(this.avatarPicUrl, this.userId)
// 上传成功后使用 vuex 保存,但不做持久处理
this.$store.commit('user_info/UpdateUserAvatarPic', this.avatarPicUrl)
},
fail: (error) => {
console.log('上传失败', error)
console.log(this.tempPicUrl)
}
})
}
})
},
async modifyUserInfoAfterUpload(avatarUrl, userId) {
const res = await modifyUserInfoAvatar(avatarUrl, userId)
console.log('调用结果:', res)
}
核心思路就是:
首先 uploadAvatarImg
将用户上传的头像保存到 oss 服务器换取图片永久链接地址,之后将该永久链接地址通过 modifyUserInfoAfterUpload
的接口函数的调用,将该永久的链接地址提交给后台。
modifyUserInfoAfterUpload 接口封装函数是这样的:
// 修改用户头像
// 请求参数:
// "avatar": "",
// "name": "",
// "phone": "",
// "sex": "",
// "signature": "",
// "userId": 0
export function modifyUserInfoAvatar(avatar, userId) {
return dgRequest.put({
url: "/user/user",
data: {
avatar,
userId
}
})
}
业务场景 2 - 用户发布动态
🗨️该功能页面的完整代码如下:
<template>
<view class="container">
<view class="container-header">
<view @click="submitAll" class="submit-btn">发布</view>
</view>
<textarea
class="container-textarea"
v-model="momentContent"
placeholder="在这里你不用害怕被看见,可以释放你的分享欲..."
>
</textarea>
<view class="image-container">
<!-- 将 + 图标也视为一个图片项 -->
<block v-for="(img, index) in ossImgsUrl" :key="index">
<image
class="image-item"
:src="img"
style="padding: 5rpx;"
@click="deleteImage(index)"
>
</image>
</block>
<view class="icon-container" @tap="chooseImage" style="padding: 5rpx;" v-if="momentPicture.length < 9">
<view class="image-addIcon"></view>
</view>
</view>
<view class="container-footer"></view>
</view>
</template>
<script>
import { addDynamic } from '../../services/AboutDynamics.js'
export default {
data() {
return {
userId: null,
momentContent: "", // 动态内容
momentPicture: [], // 选中的图片路径数组
serverUrl: "http://localhost:8080/user/common/upload", // 图片上传接口
ossImgsUrl: []
}
},
mounted() {
uni.getStorage({
key: 'userId',
success: (res) => {
console.log(res.data)
this.userId = res.data
}
})
},
methods: {
async submitAll() {
const res = await addDynamic(this.momentContent, this.ossImgsUrl, this.userId)
console.log(res)
if(res.code === 200) {
uni.switchTab({
url: "../../pages/add/add"
})
}
},
chooseImage() {
// 选取图片列表
uni.chooseImage({
count: 9,
success: (res) => {
console.log(res.tempFilePaths)
res.tempFilePaths.forEach((item, index) => {
this.momentPicture.push(item)
// 上传图片
uni.uploadFile({
url: this.serverUrl, // 上传文件的接口地址
filePath: item, // 要上传的文件路径
name: 'file', // 文件对应的key,后端可以通过这个key获取文件
header: {
// 设置用户访问的token信息
"authentication": uni.getStorageSync('token')
},
success: (uploadRes) => {
console.log(uploadRes)
let data = JSON.parse(uploadRes.data) // 后端返回给我的是一个字符串,处理一下
console.log(data)
// 将得到的在线地址保存到要提交的图片列表里
this.ossImgsUrl.push(data.data)
},
fail: (err) => {
console.error(err);
// 在这里可以处理上传失败后的逻辑
}
});
});
},
});
},
deleteImage(index) {
uni.showModal({
title: "提示",
content: "确定要删除这张图片吗?",
success: (res) => {
if (res.confirm) {
this.momentPicture.splice(index, 1)
}
},
})
},
}
}
</script>
<style lang="scss" scoped>
.container {
width: 90vw;
margin: 0 auto;
.container-header {
display: flex;
height: 50rpx;
width: 100%;
justify-content: flex-end;
.submit-btn {
width: 120rpx;
height: 50rpx;
background-color: deepskyblue;
color: #fff;
font-size: x-small;
text-align: center;
line-height: 50rpx;
border-radius: 20rpx;
margin: 20rpx 20rpx 0 0;
}
}
.container-textarea {
width: 100%;
box-shadow: 1px 1px 7rpx 2rpx rgba(0, 0, 0, 0.1);
margin-top: 35rpx;
border-radius: 20rpx;
box-sizing: border-box;
padding: 30rpx;
}
.image-container {
width: 100%;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
margin-top: 30rpx;
.image-item {
width: 30%;
height: 200rpx;
}
.icon-container {
display: flex;
justify-content: center;
align-items: center;
width: 30%;
height: 200rpx;
border-radius: 15rpx;
background-color: #eee;
.image-addIcon {
width: 80rpx;
height: 80rpx;
background-color: rgba(0,0,0,.2);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
&::before,
&::after {
content: "";
position: absolute;
width: 60rpx;
height: 8rpx;
background-color: white;
border-radius: 4rpx;
}
&::before {
transform: rotate(90deg);
}
}
}
}
.container-footer {
height: 200rpx;
}
}
</style>
🗨️该核心代码如下:
async submitAll() {
const res = await addDynamic(this.momentContent, this.ossImgsUrl, this.userId)
console.log(res)
if(res.code === 200) {
uni.switchTab({
url: "../../pages/add/add"
})
}
},
chooseImage() {
// 选取图片列表
uni.chooseImage({
count: 9,
success: (res) => {
console.log(res.tempFilePaths)
res.tempFilePaths.forEach((item, index) => {
this.momentPicture.push(item)
// 上传图片
uni.uploadFile({
url: this.serverUrl, // 上传文件的接口地址
filePath: item, // 要上传的文件路径
name: 'file', // 文件对应的key,后端可以通过这个key获取文件
header: {
// 设置用户访问的token信息
"authentication": uni.getStorageSync('token')
},
success: (uploadRes) => {
console.log(uploadRes)
let data = JSON.parse(uploadRes.data) // 后端返回给我的是一个字符串,处理一下
console.log(data)
// 将得到的在线地址保存到要提交的图片列表里
this.ossImgsUrl.push(data.data)
},
fail: (err) => {
console.error(err);
// 在这里可以处理上传失败后的逻辑
}
});
});
},
});
},
也是很简单的,就是用户使用 foreach 方法,实际还是一个单文件上传,用户选择图片,将图片临时链接数组遍历,进行单文件上传,得到永久地址,组成一个集合就行,最后 submitAll 调用接口函数 addDynamic。
addDynamic 封装如下:
// 添加动态接口A
// "categoryId": 0,
// "momentContent": "",
// "momentCreateDate": "",
// "momentId": 0,
// "momentPicture": [],
// "userId": 0
export function addDynamic(momentContent, momentPicture, userId) {
return dgRequest.put({
url: "/user/moment/addMoment",
data: {
momentContent,
momentPicture,
userId
}
})
}
结语
天气很冷,大家记得多穿衣,继续加油呀,可以放松,但不可以放弃❤️