完成效果如图
点击修改头像可以选择从相册选择图片或拍照
点击昵称可以修改昵称
点击地址跳转到地址选择界面
一、修改头像
1.wxml文件部分代码
黄色背景与头像图片、修改头像字样
<!-- 外层的view标签,作为整体内容的容器 -->
<view>
<!-- 内部的一个class为"top"的view,用于布局页面顶部相关元素 -->
<view class="top">
<!-- 一个image标签,用于展示头像图片。绑定了点击事件"sculpture",点击头像可触发相应操作。通过{{avatarUrl}}绑定数据,从页面的data中获取头像的链接地址来显示具体头像图片,同时设置了类名"top_img"用于样式控制 -->
<image bindtap="sculpture" class="top_img" src="{{avatarUrl}}"></image>
<!-- 一个view标签,同样绑定了点击事件"sculpture",文本内容为"修改头像",点击此处也能触发和点击头像图片一样的操作,用于给用户提供明确的修改头像提示 -->
<view bindtap="sculpture">修改头像</view>
</view>
</view>
图片上传方式选择
<!-- 这是用于展示头像相关操作选项的部分,比如选择头像的方式等,整体以对话框形式呈现 -->
<view class="zan-dialog {{ showdDialog? 'zan-dialog--show' : '' }}" catchtouchmove='ture'>
<!-- 这是对话框的遮罩层部分,点击它会触发绑定的"hidedType"函数,用于隐藏整个对话框,起到点击遮罩层关闭对话框的作用 -->
<view class="zan-dialog__mask" bindtap="hidedType" />
<!-- 这是对话框的内容容器,内部放置了各种头像操作相关的选项视图 -->
<view class="zan-dialog__container">
<!-- 一个视图元素,绑定了"chooseImage"点击事件,点击它可以触发从相册选择头像图片的操作,通过设置样式使其距离顶部有一定间距 -->
<view bindtap="chooseImage" style="margin-top: 40rpx;">从相册选择</view>
<!-- 一个视图元素,绑定了"takePhoto"点击事件,点击它可触发调用摄像头拍照获取头像图片的操作,同样设置了距离顶部的间距样式 -->
<view bindtap="takePhoto" style="margin-top: 40rpx;">拍照</view>
<!-- 一个视图元素,设置了顶部边框样式模拟分割线效果,并且绑定了"hidedType"点击事件,点击它可以触发隐藏对话框的操作,也就是起到取消当前操作、关闭对话框的作用,同样设置了距离顶部的间距以及顶部内边距样式 -->
<view style="margin-top: 40rpx;border-top: solid 10px rgb(241, 239, 239);padding-top: 40rpx;" bindtap="hidedType">取消</view>
</view>
</view>
2.wxss文件部分代码
黄色背景与头像图片格式
/* 类名为.top 的样式规则,用于设置具有该类名元素的样式 */
.top {
/* 设置背景颜色为橙色(#F5A623) */
background: #F5A623;
/* 将元素设置为弹性盒子布局,子元素可以按照弹性布局的规则进行排列 */
display: flex;
/* 设置弹性盒子的主轴方向为垂直方向,也就是子元素会从上到下依次排列 */
flex-direction: column;
/* 让子元素在主轴(垂直方向)上居中对齐 */
justify-content: center;
/* 让子元素在交叉轴(水平方向)上居中对齐 */
align-items: center;
/* 设置该元素底部外边距为 20rpx,用于和下方元素隔开一定距离 */
margin-bottom: 20rpx;
/* 为元素添加阴影效果,四个参数分别表示水平偏移量、垂直偏移量、模糊半径、扩展半径,最后一个参数是阴影颜色及透明度,这里是黑色半透明阴影 */
box-shadow: 5px 5px 5px 5px rgba(0, 0, 0, 0.3);
/* 设置元素顶部内边距为 20rpx,增加内部空间,避免内容紧贴顶部边缘 */
padding-top: 20rpx;
/* 设置元素底部内边距为 20rpx,增加内部空间,避免内容紧贴底部边缘 */
padding-bottom: 20rpx;
}
/* 类名为.top_img 的样式规则,用于设置具有该类名元素(通常是图片元素)的样式 */
.top_img {
/* 设置元素的上下外边距为 20rpx,左右外边距也为 20rpx,用于调整元素在父容器中的位置 */
margin: 20rpx;
/* 设置元素的宽度为 200rpx,用于控制图片的宽度大小 */
width: 200rpx;
/* 设置元素的高度为 200rpx,用于控制图片的高度大小 */
height: 200rpx;
/* 将元素的四个角设置为圆角,且半径为元素宽度或高度的一半,使其呈现圆形效果,通常用于头像图片等的样式设置 */
border-radius: 50%;
/* 设置元素右侧外边距为 40rpx,用于和右侧的其他元素(比如文字等)隔开一定距离 */
margin-right: 40rpx;
/* 为元素添加一个 1px 宽的灰色实线边框,用于装饰元素边缘 */
border: solid 1px grey;
}
图片上传方式选择部分格式
/* 类名为.zan-dialog__mask 的样式规则,用于设置对话框遮罩层的样式 */
.zan-dialog__mask {
/* 将元素的定位方式设置为绝对定位,使其可以相对于最近的已定位祖先元素进行定位,如果没有已定位的祖先元素,则相对于初始包含块(通常是浏览器窗口)进行定位 */
position: absolute;
/* 将元素的顶部与定位参考元素(这里可能是相对定位的对话框容器或者浏览器窗口等)的顶部对齐 */
top: 0;
/* 将元素的左侧与定位参考元素的左侧对齐 */
left: 0;
/* 将元素的右侧与定位参考元素的右侧对齐 */
right: 0;
/* 将元素的底部与定位参考元素的底部对齐,通过这样的设置,遮罩层可以覆盖整个定位参考区域 */
bottom: 0;
/* 设置元素的堆叠顺序(z-index)为 110,数值越大,元素在页面上越显示在上方,这里确保遮罩层能覆盖在其他一些元素之上 */
z-index: 110;
/* 设置遮罩层的背景颜色为半透明黑色,其中 rgba 中的最后一个参数 0.3 表示透明度,用于在显示时营造出一种遮挡下层内容且能看到部分模糊效果的视觉感受 */
background: rgba(0, 0, 0, 0.3);
/* 设置遮罩层的高度为视口高度(100vh 表示浏览器视口高度的 100%),使其能在垂直方向上完全覆盖可视区域 */
height: 100vh;
/* 设置遮罩层的宽度为 100%,使其在水平方向上能完全覆盖所在容器的宽度 */
width: 100%;
/* 初始时将遮罩层设置为不显示,后续会通过类名的添加(.zan-dialog--show)来控制其显示,实现动态显示隐藏的效果 */
display: none;
}
/* 类名为.zan-dialog__container 的样式规则,用于设置对话框内容容器的样式 */
.zan-dialog__container {
/* 将元素的定位方式设置为固定定位,使其会相对于浏览器窗口进行定位,无论页面如何滚动,它都会固定在指定位置 */
position: fixed;
/* 将元素的底部与浏览器窗口底部对齐,这里指定了初始位置在底部 */
bottom: 0rpx;
/* 设置元素的宽度为 100%,使其能占满整个水平方向的空间 */
width: 100%;
/* //弹窗布局宽 */
/* 设置元素的高度为视口高度的 30%,用于控制对话框内容区域的高度大小 */
height: 30%;
/* //弹窗布局高,与下面弹出距离transform有关 */
/* 设置元素的四个角的圆角半径,这里将右上角和右下角的半径设置为 20rpx,左上角和左下角的半径设置为 0,使得对话框呈现出顶部两角为圆角的外观效果 */
border-radius: 20rpx 20rpx 0 0;
/* 设置对话框内容容器的背景颜色为浅灰色(#f8f8f8) */
background: #f8f8f8;
/* 使用 transform 属性中的 translateY 函数将元素在垂直方向上向下移动自身高度的 300%(也就是初始时将其移出可视区域下方,隐藏起来),后续通过添加类名改变这个属性值来实现弹框弹出的动画效果 */
transform: translateY(300%);
/* 设置元素所有样式属性的过渡效果,过渡时间为 0.4 秒,过渡动画的时间曲线为 ease(先加速后减速的平滑过渡效果),用于实现弹框弹出和隐藏时的平滑动画效果 */
transition: all 0.4s ease;
/* 设置元素的堆叠顺序(z-index)为 112,确保对话框内容容器显示在遮罩层之上,因为其数值大于遮罩层的 z-index 值 */
z-index: 112;
/* 设置文本在容器内水平居中对齐 */
text-align: center;
/* 设置行高为 60rpx,影响文本的垂直对齐等视觉效果,也可用于在一定程度上撑开容器高度 */
line-height: 60rpx;
/* 设置容器顶部的内边距为 25rpx,增加内部空间,避免内容紧贴顶部边缘 */
padding-top: 25rpx;
}
/* 当元素同时具有.zan-dialog--show 和.zan-dialog__container 这两个类名时(也就是对话框显示状态下),设置对话框内容容器的样式 */
.zan-dialog--show.zan-dialog__container {
/* 将元素在垂直方向上的位置调整为初始位置(0,表示不进行垂直方向的偏移了),也就是让对话框内容容器从隐藏位置(下方移出可视区域外)移动到正常显示位置(底部对齐浏览器窗口底部),实现弹框弹出的动画效果 */
transform: translateY(0);
}
/* 当元素同时具有.zan-dialog--show 和.zan-dialog__mask 这两个类名时(也就是对话框显示状态下),设置遮罩层的样式 */
.zan-dialog--show.zan-dialog__mask {
/* 将遮罩层的 display 属性设置为 block,使其从隐藏状态(display: none)变为显示状态,覆盖在页面其他元素之上,营造出对话框显示时的遮挡效果 */
display: block;
}
二、修改昵称
1.wxml文件部分代码
<!-- 这是一个具有类名"con_wrapd"的视图容器,用于包裹下面昵称相关的元素,起到布局分组的作用 -->
<view class="con_wrapd">
<!-- 一个简单的视图元素,用于显示"昵称"文本,向用户提示下面输入框对应的内容是什么 -->
<view>昵称</view>
<!-- 一个输入框元素,用于用户输入昵称(用户名)相关内容 -->
<input type="text" class="nickname" placeholder="{{user.name}}" bindinput="getInput" value="{{name}}"></input>
<!--
type="text":表示这是一个文本类型的输入框,用于接收用户输入的文本内容。
class="nickname":为该输入框添加类名,可通过对应的CSS样式规则来设置其外观样式,比如字体、颜色、边框等。
placeholder="{{user.name}}":使用双大括号语法绑定数据,这里会将页面数据中 user 对象里的 name 属性值作为输入框的占位提示文本显示,当输入框为空时提示用户可输入的内容(可能是初始的用户名等)。
bindinput="getInput":绑定了一个名为"getInput"的输入事件,当用户在输入框中输入内容时,会触发对应的函数(在对应的JavaScript代码中应该定义了该函数),用于实时获取用户输入的值并进行相应处理,比如更新页面数据等。
value="{{name}}":同样使用双大括号绑定数据,将页面数据中的"name"属性值作为输入框当前显示的值,也就是可以实现输入框初始显示已有的用户名,并且随着用户输入实时更新页面数据里的"name"属性值。
-->
</view>
2.wxss文件部分代码
/* 类名为.nickname 的样式规则,用于设置具有该类名元素(在这里应该是那个昵称输入框元素)的样式 */
.nickname {
/* 设置元素的顶部外边距为 45rpx,使元素与上方元素隔开一定距离,增强页面布局的层次感 */
margin-top: 45rpx;
/* 设置元素内部文本水平向右对齐,符合一些特定的页面排版需求,比如让输入的内容靠右侧显示等 */
text-align: right;
/* 设置元素的宽度为 580rpx,用于控制输入框在水平方向上占据的空间大小 */
width: 580rpx;
/* 设置元素的右侧外边距为 20rpx,使元素与右侧的其他元素保持一定间隔,避免显得过于拥挤 */
margin-right: 20rpx;
}
/* 类名为.con_wrapd 的样式规则,用于设置具有该类名的外层视图容器(包裹昵称相关元素的容器)的样式 */
.con_wrapd {
/* 将元素设置为弹性盒子布局,子元素可以按照弹性布局的规则进行排列,方便实现灵活的布局效果 */
display: flex;
/* 使用 justify-content 属性设置子元素在主轴(在 flex 布局下,默认是水平方向)上的对齐方式为两端对齐,并且均匀分布剩余空间,使得"昵称"文本和昵称输入框在水平方向上合理分布,间隔均匀 */
justify-content: space-between;
/* 为元素添加底部边框,边框样式为 1px 宽的实线,颜色是浅灰色(rgb(216, 216, 216)),用于在视觉上区分不同的内容区域,增强页面的层次感和可读性 */
border-bottom: 1px solid rgb(216, 216, 216);
/* 设置元素的行高为 130rpx,影响文本在垂直方向上的对齐方式以及整个元素的高度表现等,例如让文本在垂直方向上处于合适的位置,看起来更加整齐美观 */
line-height: 130rpx;
}
三、修改地址
1.wxml文件部分代码
<!-- 这是一个具有类名"con_wrapd"的视图容器,用于包裹地址相关的元素,起到布局分组的作用 -->
<view class="con_wrapd">
<!-- 一个具有类名"addadress"的视图元素,绑定了点击事件"address",点击该元素可触发对应的函数(在对应的JavaScript代码中应该定义了该函数,用于处理地址相关操作,比如选择地址等),文本内容为"地址",用于提示用户此处可进行地址相关操作 -->
<view class="addadress" bindtap="address">
地址
</view>
<!-- 一个图片元素,用于展示一个箭头图标,绑定了点击事件"address",点击该图片同样会触发和上面视图元素一样的地址相关操作,设置了类名"jiantou",可通过对应的CSS样式规则来设置该图片的外观样式,比如大小、位置等 -->
<image src="cloud://fleamarket-7g51bean4803bb56.666c-fleamarket-7g51bean4803bb56-1330959456/weda-uploader/image/youjiantou.png" class="jiantou" bindtap="address"></image>
</view>
2.wxss文件部分代码
.con_wrapd {
display: flex;
justify-content: space-between;
border-bottom: 1px solid rgb(216, 216, 216);
line-height: 130rpx;
}
四、提交
1.wxml文件部分代码
<!-- 一个类名为“confirm”的视图容器,让相关元素在页面中形成一个相对独立且逻辑关联的区域 -->
<view class="confirm">
<!-- 一个按钮元素,使用了“btn-dl”类名,可通过对应的CSS样式规则来设置按钮的外观样式,比如按钮的颜色、大小、边框等,使其符合页面整体的视觉设计风格。
同时绑定了“submit”点击事件,意味着当用户点击这个按钮时,会触发在对应的JavaScript代码中定义的“submit”函数 -->
<button class="btn-dl" bind:tap="submit">确认修改</button>
</view>
</view>
2.wxss文件部分代码
/* 类名为.confirm 的样式规则,用于设置具有该类名的视图容器(在 HTML 中对应包裹按钮的那个 <view> 元素)的样式 */
.confirm {
/* 设置元素的宽度为 350rpx,用于控制该容器在水平方向上占据的空间大小,使其具有合适的宽度以适配页面布局 */
width: 350rpx;
/* 设置元素的高度为 80rpx,明确容器在垂直方向上的尺寸,以便为内部按钮元素提供合理的布局空间 */
height: 80rpx;
/* 设置元素顶部的外边距为 60rpx,使该容器与上方的其他页面元素隔开一定距离,增强页面的层次感和布局合理性 */
margin-top: 60rpx;
/* 将元素的左侧外边距设置为 auto,右侧外边距也设置为 auto,这样可以使该元素在其父容器中水平居中对齐,达到布局上的美观和对称效果 */
margin-left: auto;
margin-right: auto;
}
/* 类名为.btn-dl 的样式规则,用于设置具有该类名的按钮元素(在 HTML 中对应 <button> 元素)的样式 */
.btn-dl {
/* 设置元素内部的内边距为 0rpx,意味着按钮内部的文本或其他内容与按钮边框之间没有额外的间隔空间,让按钮看起来更紧凑 */
padding: 0rpx;
/* 设置元素的行高为 50rpx,会影响按钮内文本在垂直方向上的对齐方式,同时也在一定程度上影响按钮的整体高度视觉效果 */
line-height: 50rpx;
/* 设置按钮内文本的字体大小为 35rpx,控制文本显示的大小,使其清晰可读且符合页面的整体字号风格 */
font-size: 35rpx;
/* 设置按钮的宽度为 100%,使其宽度能自适应父容器(也就是上面.confirm 类对应的容器)的宽度,填满整个水平空间 */
width: 100%;
/* 设置按钮的高度为 100%,同理让按钮高度自适应父容器的高度,保证按钮能完整占据父容器的空间范围 */
height: 100%;
/* 将按钮的四个角设置为圆角,圆角半径为 50rpx,使按钮呈现出较为圆润的外观效果,增加视觉上的友好度和美感 */
border-radius: 50rpx;
/* 设置按钮的背景颜色为橙色,通过颜色来突出按钮,使其在页面中更加醒目,引导用户进行点击操作 */
background: orange;
/* 将按钮元素设置为网格布局(grid),方便对内部的子元素(虽然这里按钮内部暂时没有复杂的子元素结构,但可以方便后续拓展)进行更灵活精确的定位和排列 */
display: grid;
/* 在网格布局中,使用 justify-items 属性设置子元素在水平方向(也就是网格的列方向)上的对齐方式为居中对齐,确保按钮内的内容(如文本)在水平方向上处于中心位置 */
justify-items: center;
/* 在网格布局中,使用 align-items 属性设置子元素在垂直方向(也就是网格的行方向)上的对齐方式为居中对齐,保证按钮内的内容在垂直方向上也处于中心位置,实现整体的居中显示效果 */
align-items: center;
/* 这里又重新设置了一次宽度为 150px,与前面设置的 width: 100% 存在冲突,一般来说后面定义的样式会覆盖前面相同属性的设置,此处可能需要根据实际布局需求检查是否合理,可能是想要限制按钮的最大宽度之类的情况 */
width: 150px;
/* 同样又重新设置了一次高度为 50px,也与前面 height: 100% 冲突,可能有类似限制按钮尺寸的特定设计意图,需确认是否符合预期布局效果 */
height: 50px;
/* 为按钮添加内阴影效果,四个参数分别表示水平偏移量、垂直偏移量、模糊半径、扩展半径,最后一个参数 rgba(3, 0, 0, 0.2) 表示阴影颜色及透明度,这里是一种较暗且半透明的颜色,inset 表示是内阴影,使按钮在视觉上更具立体感和层次感 */
box-shadow: 0px 0px 10px 5px rgba(3, 0, 0, 0.2)inset;
}
五.js文件代码
// 获取小程序实例,以便访问全局数据和方法
const app = getApp();
// 初始化微信小程序云数据库实例,用于后续数据库操作
const db = wx.cloud.database();
Page({
/**
* 页面的初始数据
*/
data: {
// 用于存储用户信息对象,初始化为空对象,后续按需填充具体用户数据
user: {},
// 存放用户头像链接地址,初始为空字符串,等待从全局数据获取或更新
avatarUrl: "",
// 存储用户名,初始为空字符串,同理后续会被赋值或修改
name: "",
// 标记用户头像是否有更改,初始设为false,头像操作后按需更新
chagea: false
},
onLoad: function (options) {
// 页面加载时,从全局数据(app.globalData.users)获取用户信息,
// 并将用户名、头像链接等分别设置到页面数据中,确保页面渲染展示已有信息
this.setData({
user: app.globalData.users,
name: app.globalData.users.name,
avatarUrl: app.globalData.users.avatarUrl,
});
},
// 头像遮盖层相关函数,用于隐藏头像操作弹出层之类的界面
hidedType: function (e) {
// 将控制弹出层显示隐藏的标识showdDialog设为false,实现隐藏效果
this.setData({
showdDialog: false
})
},
// 头像操作函数,用于触发显示头像相关操作的弹出层(如选择头像来源界面)
sculpture: function (e) {
// 将控制弹出层显示隐藏的标识showdDialog设为true,展示相关界面
this.setData({
showdDialog: true
})
},
address: function () {
let that = this;
// 检查当前微信版本是否支持chooseAddress接口
if (wx.chooseAddress) {
wx.chooseAddress({
success: function (res) {
// 若成功选择地址,打印地址信息便于调试查看
console.log("地址", res);
// 将选择的地址信息更新到页面数据的address字段,方便后续使用
that.setData({
address: res
});
// 再次打印地址信息,确认数据更新成功,常用于调试
console.log(that.data.address);
},
fail: function (err) {
// 若选择地址失败,将错误信息转为字符串打印,辅助排查问题
console.log(JSON.stringify(err))
}
})
} else {
// 若当前微信版本不支持该接口,打印提示信息告知情况
console.log('当前微信版本不支持chooseAddress');
}
},
// 从相册选择头像图片的函数
chooseImage: function () {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sizeType: ['compressed'], // 明确选择压缩图,节省资源、加快加载
sourceType: ['album'], // 指定图片来源为相册
success: (res) => {
// 打印选择图片成功信息及返回数据,方便调试查看图片详情
console.log("选择图片成功", res);
// 将选择的图片临时文件路径更新到avatarUrl,标记头像已更换
this.setData({
avatarUrl: res.tempFiles[0].tempFilePath,
chagea: true
});
}
});
// 隐藏头像操作弹出层(完成选择后关闭相关界面)
this.setData({
showdDialog: false
});
},
// 通过拍照获取头像图片的函数
takePhoto: function () {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sizeType: ['compressed'], // 同样选择压缩图
sourceType: ['camera'], // 指定图片来源为相机拍摄
success: (res) => {
// 打印选择图片成功信息及返回数据,辅助调试
console.log("选择图片成功", res);
// 更新头像链接为拍摄图片临时路径,标记头像更改
this.setData({
avatarUrl: res.tempFiles[0].tempFilePath,
chagea: true
});
}
});
// 隐藏头像操作弹出层
this.setData({
showdDialog: false
});
},
getInput: function (e) {
// 打印输入框输入值,方便查看用户输入内容,常用于调试
console.log(e.detail.value);
// 将输入框输入的值更新到页面数据的name字段,实现用户名修改
this.setData({
name: e.detail.value
});
},
submit: function () {
let user = this.data.user;
let name = this.data.name;
let filePath = this.data.avatarUrl;
let suffix = /\.[^\.]+$/.exec(filePath)[0]; // 正则获取头像文件扩展名,用于云存储命名
if (this.data.chagea) {
wx.cloud.uploadFile({
cloudPath: new Date().getTime() + suffix,
filePath: filePath, // 要上传的头像文件路径
}).then(res => {
let fileID = res.fileID;
// 打印上传结果(文件ID),便于跟踪上传状态
console.log("上传结果", fileID);
// 更新云数据库中用户文档的头像链接和用户名
db.collection('user').doc(user._id)
.update({
data: {
name: name,
avatarUrl: fileID
}
}).then(res => {
// 打印修改结果,辅助确认数据库更新成功
console.log('修改结果', res);
return db.collection('user').doc(user._id)
.get()
.then(res => {
let user = res.data;
// 将更新后的用户数据同步到全局数据
app.globalData.users = user;
// 打印全局变量更新情况,调试查看
console.log('全局变量已更新', app.globalData.users);
// 切换页面到'../me/me',完成信息修改后的跳转
wx.switchTab({
url: '../me/me'
});
});
});
})
} else {
// 若头像未更改,仅更新用户名到云数据库
db.collection('user').doc(user._id)
.update({
data: {
name: name,
}
}).then(res => {
// 打印修改结果,确认更新
console.log('修改结果', res);
return db.collection('user').doc(user._id)
.get()
.then(res => {
let user = res.data;
// 同步更新后的用户数据到全局数据
app.globalData.users = user;
// 打印全局变量更新情况
console.log('全局变量已更新', app.globalData.users);
// 切换页面
wx.switchTab({
url: '../me/me'
});
});
});
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
这段代码构建了微信小程序中一个用户信息管理页面的核心逻辑。通过 onLoad
函数在页面加载时引入全局用户信息展示基础数据,包含头像和用户名。围绕头像有一系列操作函数,sculpture
触发头像操作界面显示,chooseImage
和 takePhoto
分别支持从相册选图、拍照获取头像并更新页面数据,hidedType
隐藏相关界面。address
函数用于获取用户地址(依微信版本支持情况)并更新页面数据。getInput
能捕获输入值更新用户名。submit
函数是关键,依据头像是否更改决定是单纯更新用户名还是连头像一起更新到云数据库,更新后同步全局数据并切换页面回 ../me/me
。