uniapp实战 -- 个人信息维护(含选择图片 uni.chooseMedia,上传文件 uni.uploadFile,获取和更新表单数据)

本文主要是介绍uniapp实战 -- 个人信息维护(含选择图片 uni.chooseMedia,上传文件 uni.uploadFile,获取和更新表单数据),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

效果预览

在这里插入图片描述

在这里插入图片描述

相关代码

页面–我的

src\pages\my\my.vue

    <!-- 个人资料 --><view class="profile" :style="{ paddingTop: safeAreaInsets!.top + 'px' }"><!-- 情况1:已登录 --><view class="overview" v-if="memberStore.profile"><navigator url="/pagesMember/profile/profile" hover-class="none"><image class="avatar" mode="aspectFill" :src="memberStore.profile.avatar"></image></navigator><view class="meta"><view class="nickname">{{ memberStore.profile.nickname || memberStore.profile.account }}</view><navigator class="extra" url="/pagesMember/profile/profile" hover-class="none"><text class="update">更新头像昵称</text></navigator></view></view><!-- 情况2:未登录 --><view class="overview" v-else><navigator url="/pages/login/login" hover-class="none"><imageclass="avatar gray"mode="aspectFill"src="http://yjy-xiaotuxian-dev.oss-cn-beijing.aliyuncs.com/picture/2021-04-06/db628d42-88a7-46e7-abb8-659448c33081.png"></image></navigator><view class="meta"><navigator url="/pages/login/login" hover-class="none" class="nickname">未登录</navigator><view class="extra"><text class="tips">点击登录账号</text></view></view></view><navigator class="settings" url="/pagesMember/settings/settings" hover-class="none">设置</navigator></view>
/* 用户信息 */
.profile {margin-top: 20rpx;position: relative;.overview {display: flex;height: 120rpx;padding: 0 36rpx;color: #fff;}.avatar {width: 120rpx;height: 120rpx;border-radius: 50%;background-color: #eee;}.gray {filter: grayscale(100%);}.meta {display: flex;flex-direction: column;justify-content: center;align-items: flex-start;line-height: 30rpx;padding: 16rpx 0;margin-left: 20rpx;}.nickname {max-width: 350rpx;margin-bottom: 16rpx;font-size: 30rpx;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.extra {display: flex;font-size: 20rpx;}.tips {font-size: 22rpx;}.update {padding: 3rpx 10rpx 1rpx;color: rgba(255, 255, 255, 0.8);border: 1rpx solid rgba(255, 255, 255, 0.8);margin-right: 10rpx;border-radius: 30rpx;}.settings {position: absolute;bottom: 0;right: 40rpx;font-size: 30rpx;color: #fff;}
}
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()import { useMemberStore } from '@/stores'// 获取会员信息
const memberStore = useMemberStore()

页面–个人信息维护

src\pagesMember\profile\profile.vue

<script setup lang="ts">
import { getMemberProfileAPI, putMemberProfileAPI } from '@/apis/profile'
import type { Gender, ProfileDetail } from '@/types/member'
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()// 获取个人信息,修改个人信息需提供初始值 (使用 as 进行类型断言,不用再声明类型)
const profile = ref({} as ProfileDetail)
const getMemberProfileData = async () => {const res = await getMemberProfileAPI()profile.value = res.result
}onLoad(() => {getMemberProfileData()
})import { useMemberStore } from '@/stores'// 获取会员信息
const memberStore = useMemberStore()// 修改头像
const onAvatarChange = () => {// 调用拍照/选择图片uni.chooseMedia({// 文件个数count: 1,// 文件类型mediaType: ['image'],success: (res) => {// 本地路径const { tempFilePath } = res.tempFiles[0]// 文件上传uni.uploadFile({url: '/member/profile/avatar',name: 'file', // 后端数据字段名filePath: tempFilePath, // 新头像success: (res) => {// 判断状态码是否上传成功if (res.statusCode === 200) {// 提取头像const { avatar } = JSON.parse(res.data).result// 当前页面更新头像profile.value!.avatar = avatar// 更新 Store 头像memberStore.profile!.avatar = avataruni.showToast({ icon: 'success', title: '更新成功' })} else {uni.showToast({ icon: 'error', title: '出现错误' })}},})},})
}// 修改性别
const onGenderChange: UniHelper.RadioGroupOnChange = (ev) => {profile.value.gender = ev.detail.value as Gender
}// 修改生日
const onBirthdayChange: UniHelper.DatePickerOnChange = (ev) => {profile.value.birthday = ev.detail.value
}// 修改城市
let fullLocationCode: [string, string, string] = ['', '', '']
const onFullLocationChange: UniHelper.RegionPickerOnChange = (ev) => {// 修改前端界面profile.value.fullLocation = ev.detail.value.join(' ')// 提交后端更新fullLocationCode = ev.detail.code!
}// 点击保存提交表单
const onSubmit = async () => {const { nickname, gender, birthday, profession } = profile.valueconst res = await putMemberProfileAPI({nickname,gender,birthday,profession,provinceCode: fullLocationCode[0],cityCode: fullLocationCode[1],countyCode: fullLocationCode[2],})// 更新Store昵称memberStore.profile!.nickname = res.result.nicknameuni.showToast({ icon: 'success', title: '保存成功' })setTimeout(() => {uni.navigateBack()}, 400)
}
</script><template><view class="viewport"><!-- 导航栏 --><view class="navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }"><navigator open-type="navigateBack" class="back icon-left" hover-class="none"></navigator><view class="title">个人信息</view></view><!-- 头像 --><view class="avatar"><view class="avatar-content" @tap="onAvatarChange"><image class="image" :src="profile?.avatar" mode="aspectFill" /><text class="text">点击修改头像</text></view></view><!-- 表单 --><view class="form"><!-- 表单内容 --><view class="form-content"><view class="form-item"><text class="label">账号</text><text class="account">{{ profile?.account }}</text></view><view class="form-item"><text class="label">昵称</text><input class="input" type="text" placeholder="请填写昵称" v-model="profile.nickname" /></view><view class="form-item"><text class="label">性别</text><radio-group @change="onGenderChange"><label class="radio"><radio value="" color="#27ba9b" :checked="profile?.gender === '男'" /></label><label class="radio"><radio value="" color="#27ba9b" :checked="profile?.gender === '女'" /></label></radio-group></view><view class="form-item"><text class="label">生日</text><pickerclass="picker"mode="date":value="profile?.birthday"start="1900-01-01":end="new Date()"@change="onBirthdayChange"><view v-if="profile?.birthday">{{ profile?.birthday }}</view><view class="placeholder" v-else>请选择日期</view></picker></view><view class="form-item"><text class="label">城市</text><picker@change="onFullLocationChange"class="picker":value="profile?.fullLocation?.split(' ')"mode="region"><view v-if="profile?.fullLocation">{{ profile.fullLocation }}</view><view class="placeholder" v-else>请选择城市</view></picker></view><view class="form-item"><text class="label">职业</text><input class="input" type="text" placeholder="请填写职业" v-model="profile.profession" /></view></view><!-- 提交按钮 --><button class="form-button" @tap="onSubmit">保 存</button></view></view>
</template>
<style lang="scss">
page {background-color: #f4f4f4;
}.viewport {display: flex;flex-direction: column;height: 100%;background-image: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/order_bg.png);background-size: auto 420rpx;background-repeat: no-repeat;
}// 导航栏
.navbar {position: relative;.title {height: 40px;display: flex;justify-content: center;align-items: center;font-size: 16px;font-weight: 500;color: #fff;}.back {position: absolute;height: 40px;width: 40px;left: 0;font-size: 20px;color: #fff;display: flex;justify-content: center;align-items: center;}
}// 头像
.avatar {text-align: center;width: 100%;height: 260rpx;display: flex;flex-direction: column;justify-content: center;align-items: center;.image {width: 160rpx;height: 160rpx;border-radius: 50%;background-color: #eee;}.text {display: block;padding-top: 20rpx;line-height: 1;font-size: 26rpx;color: #fff;}
}// 表单
.form {background-color: #f4f4f4;&-content {margin: 20rpx 20rpx 0;padding: 0 20rpx;border-radius: 10rpx;background-color: #fff;}&-item {display: flex;height: 96rpx;line-height: 46rpx;padding: 25rpx 10rpx;background-color: #fff;font-size: 28rpx;border-bottom: 1rpx solid #ddd;&:last-child {border: none;}.label {width: 180rpx;color: #333;}.account {color: #666;}.input {flex: 1;display: block;height: 46rpx;}.radio {margin-right: 20rpx;}.picker {flex: 1;}.placeholder {color: #808080;}}&-button {height: 80rpx;text-align: center;line-height: 80rpx;margin: 30rpx 20rpx;color: #fff;border-radius: 80rpx;font-size: 30rpx;background-color: #27ba9b;}
}
</style>

接口

src\apis\profile.ts

import type { ProfileDetail, ProfileParams } from '@/types/member'
import { http } from '@/utils/http'/*** 获取个人信息*/
export const getMemberProfileAPI = () => {return http<ProfileDetail>({method: 'GET',url: '/member/profile',})
}/*** 修改个人信息* @param data 请求体参数*/
export const putMemberProfileAPI = (data: ProfileParams) => {return http<ProfileDetail>({method: 'PUT',url: '/member/profile',data,})
}

类型声明

src\types\member.d.ts

/** 封装通用信息 */
type BaseProfile = {/** 用户ID */id: number/** 头像  */avatar: string/** 账户名  */account: string/** 昵称 */nickname?: string
}/** 小程序登录 登录用户信息 */
export type LoginResult = BaseProfile & {/** 用户ID */id: number/** 头像  */avatar: string/** 账户名  */account: string/** 昵称 */nickname?: string/** 手机号 */mobile: string/** 登录凭证 */token: string
}/** 个人信息 用户详情信息 */
export type ProfileDetail = BaseProfile & {/** 性别 */gender?: Gender/** 生日 */birthday?: string/** 省市区 */fullLocation?: string/** 职业 */profession?: string
}
/** 性别 */
export type Gender = '女' | '男'/** 个人信息 修改请求体参数 */
export type ProfileParams = Pick<ProfileDetail,'nickname' | 'gender' | 'birthday' | 'profession'
> & {/** 省份编码 */provinceCode?: string/** 城市编码 */cityCode?: string/** 区/县编码 */countyCode?: string
}

持久化本地存储 store

src\stores\index.ts

import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'// 创建 pinia 实例
const pinia = createPinia()
// 使用持久化存储插件
pinia.use(persist)// 默认导出,给 main.ts 使用
export default pinia// 模块统一导出
export * from './modules/member'

src\stores\modules\member.ts

import { defineStore } from 'pinia'
import { ref } from 'vue'// 定义 Store
export const useMemberStore = defineStore('member',() => {// 会员信息const profile = ref<any>()// 保存会员信息,登录时使用const setProfile = (val: any) => {profile.value = val}// 清理会员信息,退出时使用const clearProfile = () => {profile.value = undefined}// 记得 returnreturn {profile,setProfile,clearProfile,}},// 持久化{persist: {// 调整为兼容多端的APIstorage: {setItem(key, value) {uni.setStorageSync(key, value)},getItem(key) {return uni.getStorageSync(key)},},},},
)

这篇关于uniapp实战 -- 个人信息维护(含选择图片 uni.chooseMedia,上传文件 uni.uploadFile,获取和更新表单数据)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/525403

相关文章

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

SpringBoot服务获取Pod当前IP的两种方案

《SpringBoot服务获取Pod当前IP的两种方案》在Kubernetes集群中,SpringBoot服务获取Pod当前IP的方案主要有两种,通过环境变量注入或通过Java代码动态获取网络接口IP... 目录方案一:通过 Kubernetes Downward API 注入环境变量原理步骤方案二:通过

Python基于微信OCR引擎实现高效图片文字识别

《Python基于微信OCR引擎实现高效图片文字识别》这篇文章主要为大家详细介绍了一款基于微信OCR引擎的图片文字识别桌面应用开发全过程,可以实现从图片拖拽识别到文字提取,感兴趣的小伙伴可以跟随小编一... 目录一、项目概述1.1 开发背景1.2 技术选型1.3 核心优势二、功能详解2.1 核心功能模块2.

使用SpringBoot整合Sharding Sphere实现数据脱敏的示例

《使用SpringBoot整合ShardingSphere实现数据脱敏的示例》ApacheShardingSphere数据脱敏模块,通过SQL拦截与改写实现敏感信息加密存储,解决手动处理繁琐及系统改... 目录痛点一:痛点二:脱敏配置Quick Start——Spring 显示配置:1.引入依赖2.创建脱敏

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

使用Python实现base64字符串与图片互转的详细步骤

《使用Python实现base64字符串与图片互转的详细步骤》要将一个Base64编码的字符串转换为图片文件并保存下来,可以使用Python的base64模块来实现,这一过程包括解码Base64字符串... 目录1. 图片编码为 Base64 字符串2. Base64 字符串解码为图片文件3. 示例使用注意

使用Python实现获取屏幕像素颜色值

《使用Python实现获取屏幕像素颜色值》这篇文章主要为大家详细介绍了如何使用Python实现获取屏幕像素颜色值,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、一个小工具,按住F10键,颜色值会跟着显示。完整代码import tkinter as tkimport pyau

详解如何使用Python构建从数据到文档的自动化工作流

《详解如何使用Python构建从数据到文档的自动化工作流》这篇文章将通过真实工作场景拆解,为大家展示如何用Python构建自动化工作流,让工具代替人力完成这些数字苦力活,感兴趣的小伙伴可以跟随小编一起... 目录一、Excel处理:从数据搬运工到智能分析师二、PDF处理:文档工厂的智能生产线三、邮件自动化: