技术栈:Uniapp + Vue3 + uview-plus
简介
因实际需求,需要本小程序支持用户修改默认的头像、用户名,其中还需支持获取微信账号的头像、昵称。
原本可直接获取昵称、头像的 wx.getUserInfo与 open-type=“getUserInfo” 获取用户个人信息(头像、昵称、性别与地区),权限已经被微信收回。
具体可查看微信官方文档:

但是微信单独提供了接口来支持替换此功能
- getUserProfile
- button 配置 open-type=“chooseAvatar” @chooseavatar=“onChooseavatar”
- input 配置 type=“nickname”
实现
获取微信头像
为了页面显示效果和功能实现,需要使用 button包裹住头像,button 配置 相关属性,chooseavatar 内接收、处理图片路径。
<up-cell-group>
<up-cell :isLink="false">
<template #title> <view class="title">头像</view> </template>
<template #value>
<button
class="avatar-btn"
style="border-radius: 50%"
open-type="chooseAvatar"
@chooseavatar="onChooseavatar"
>
<up-avatar :src="infoForm.avatar" :size="64"></up-avatar>
</button>
</template>
</up-cell>
</up-cell-group>
import { reactive } from "vue";
const infoForm = reactive({ avatar: "" });
// 选择头像|手机内其他图片
const onChooseavatar = (e) => {
new Promise((resolve, reject) => {
// 获取图片信息(临时路径)
uni.getImageInfo({
src: e.detail.avatarUrl,
success: (res) => {
// console.log("图片信息", res)
resolve(res);
},
fail: (err) => {
// console.error("获取图片信息失败了", err)
reject(err);
},
});
})
.then((res) => {
return Promise.resolve({
tempFilePath: e.detail.avatarUrl,
});
})
.then((res) => {
infoForm.avatar = e.detail.avatarUrl;
// 上传头像到服务器
// return uploadAvatar(res).then((res) => {
// infoForm.avatar = res.url;
// });
})
.catch((err) => {
// 获取失败时使用store内默认头像
// infoForm.avatar = userStore.userInfo.avatar
});
};
获取微信昵称
获取微信昵称就相对比较简单,只需要input配置type=“nickname” 即可,其他按照正常逻辑。
<up-form
labelPosition="left"
:labelWidth="100"
:model="infoForm"
ref="formRef"
>
<up-form-item
label="用户名"
prop="nickName"
ref="nickName"
borderBottom
>
<up-input
v-model="infoForm.nickName"
border="none"
type="nickname"
fontSize="28rpx"
color="#666666"
clearable
></up-input>
</up-form-item>
</up-form>
import { ref, reactive } from "vue";
const infoForm = reactive({
nickName: "",
});
效果
最终实现效果


完整代码
修改头像
<template>
<view class="wrap">
<div class="edit-main-box">
<up-cell-group>
<up-cell :isLink="false">
<template #title> <view class="title">头像</view> </template>
<template #value>
<button
class="avatar-btn"
style="border-radius: 50%"
open-type="chooseAvatar"
@chooseavatar="onChooseavatar"
>
<up-avatar :src="infoForm.avatar" :size="64"></up-avatar>
</button>
</template>
<template #right-icon>
<image class="Expand_left-img" src="@/static/svg-icons/Expand_left.svg"></image>
</template>
</up-cell>
<view class="info-line"></view>
<u-cell :isLink="false" >
<template #title> <view class="title">用户名</view> </template>
<template #value
><view class="value" @click="toEditName">{{ infoForm.nickName }}</view>
</template>
<template #right-icon>
<image class="Expand_left-img" src="@/static/svg-icons/Expand_left.svg" @click="toEditName"></image>
</template>
</u-cell>
</up-cell-group>
</div>
</view>
</template>
<script setup>
import { reactive } from "vue";
import { onShow } from "@dcloudio/uni-app";
// store中用户信息
import { useUserStore } from "@/stores/user";
const userStore = useUserStore();
const infoForm = reactive({
avatar: "",
nickName: "",
});
onShow(() => {
infoForm.avatar = userStore.userInfo.avatar;
infoForm.nickName = userStore.userInfo.nickName;
});
// 上传头像
const uploadAvatar = (res) => {
return new Promise(async (resolve, reject) => {
// 上传用户头像到服务器
// const result = await uploadFile(res.tempFilePath, "user-avatar");
// resolve({
// url: result,
// });
});
};
// 选择头像
const onChooseavatar = (e) => {
new Promise((resolve, reject) => {
uni.getImageInfo({
src: e.detail.avatarUrl,
success: (res) => {
// console.log("图片尺寸", res)
resolve(res);
},
fail: (err) => {
// console.error("获取图片信息失败了", err)
reject(err);
},
});
})
.then((res) => {
return Promise.resolve({
tempFilePath: e.detail.avatarUrl,
});
})
.then((res) => {
infoForm.avatar = e.detail.avatarUrl;
return uploadAvatar(res).then((res) => {
infoForm.avatar = res.url;
updateInfo();
});
})
.catch((err) => (infoForm.avatar = userStore.userInfo.avatar)); // 失败恢复
};
// 去编辑用户名页面
const toEditName = () => {
// router.navigateTo("/pages/editInfo/editName", {
// defaultNickName: infoForm.nickName,
// });
};
</script>
<style scoped lang="scss">
.wrap {
background-color: #f3f4f6;
min-height: 100vh;
padding: 0 28rpx;
// padding-bottom: 150rpx;
padding-top: 28rpx;
}
.edit-main-box {
// margin: 20rpx 28rpx;
background: #fff;
border-radius: 8px;
.info-line {
width: calc(100% - 56rpx);
margin: 0 28rpx;
height: 2rpx;
background: #f5f5f6;
}
:deep(.u-line) {
display: none;
}
.avatar-btn {
padding: 0;
border-radius: 50%;
}
.title {
font-family: "PingFang SC";
font-size: 28rpx;
font-weight: 500;
line-height: normal;
color: #333333;
width: 150rpx;
}
.value {
font-family: "PingFang SC";
font-size: 28rpx;
font-weight: normal;
line-height: normal;
letter-spacing: 0px;
font-variation-settings: "opsz" auto;
color: #666666;
}
.Expand_left-img {
width: 44rpx;
height: 44rpx;
}
}
</style>
修改昵称
<template>
<view class="wrap">
<up-toast ref="uToastRef"></up-toast>
<view class="main-box">
<up-form
labelPosition="left"
:labelStyle="labelStyle"
:labelWidth="100"
:model="infoForm"
ref="formRef"
>
<up-form-item
label="用户名"
prop="nickName"
ref="nickName"
borderBottom
>
<up-input
v-model="infoForm.nickName"
border="none"
type="nickname"
fontSize="28rpx"
color="#666666"
clearable
@change="changeInput"
></up-input>
</up-form-item>
</up-form>
</view>
<view class="edit-name-limit">用户名限制1-20个字符</view>
<view class="btn-edit-name">
<button
class="btn-edit-name-btn"
:style="{ opacity: isDis ? 0.2 : 1 }"
:disabled="isDis"
@click="updateInfo"
>
确定
</button>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from "vue";
import { onLoad } from "@dcloudio/uni-app";
// store中用户信息
import { useUserStore } from "@/stores/user";
const infoForm = reactive({
nickName: "",
});
const uToastRef = ref(null);
const userStore = useUserStore();
const isDis = ref(false);
const labelStyle = ref({
"font-size": "28rpx",
"font-weight": 600,
color: "#3B3D3D",
});
onLoad(() => {
infoForm.nickName = userStore.userInfo.nickName;
});
// 输入为空时禁用
const changeInput = (value) => {
if (!value) isDis.value = true;
else isDis.value = false;
}
// 更新用户名
const updateInfo = () => {
if (infoForm.nickName.length > 20) {
// ("用户名太长,最多20个字符"); // uniapp弹窗
uToastRef.value.show({
type: 'default',
message: "用户名太长,最多20个字符",
});
return;
}
// 请求更新用户信息接口
};
</script>
<style scoped lang="scss">
.wrap {
background-color: #f3f4f6;
min-height: 100vh;
padding: 0 28rpx;
padding-top: 28rpx;
// padding-bottom: 150rpx;
.main-box {
background: #fff;
border-radius: 8px;
padding: 10rpx 14rpx;
:deep(.u-line) {
display: none;
}
}
.edit-name-limit {
font-family: "PingFang SC";
font-size: 12px;
color: #999999;
margin-top: 32rpx;
margin-bottom: 80rpx;
}
.btn-edit-name-btn {
width: 100%;
border-radius: 8px;
background: #ff0046;
height: 96rpx;
border-radius: 8px;
padding-top: 28rpx;
padding-bottom: 28rpx;
font-family: "PingFang SC";
font-weight: 500;
line-height: normal;
font-size: 28rpx;
color: #ffffff;
border: none;
&::after {
border: unset;
}
}
.btn-edit-name-btn:disabled {
cursor: not-allowed; /* 更改鼠标指针为禁止符号 */
background: rgba(255, 0, 70, 0.2);
box-shadow: none; /* 移除阴影 */
/* 可以添加其他属性来进一步更改按钮的禁用样式,如边框颜色、文本颜色等 */
}
}
</style>



2608

被折叠的 条评论
为什么被折叠?



