前言
在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 } }) }
结语
天气很冷,大家记得多穿衣,继续加油呀,可以放松,但不可以放弃❤️