初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)
本文总结了前端开发的四个关键方面:1)明确需求逻辑、页面组件复用和接口调用注意事项;2)OSS图片上传的接口限制、平台适配及小程序配置;3)权限管理要点;4)表单输入和Toast提示的实现建议。重点强调了开发前充分理解需求、组件化思维、跨平台兼容性处理,以及及时沟通的重要性。
零、关于开发思路
(一)拿到工作任务,先理清楚需求
1.逻辑部分
不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问
2.页面部分(含国际化)
整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用
(时间充分的前提下,不要一味先复制粘贴再提取;要先提取直接使用)
开发过程中就国际化,可以仅把中文国际化做了zh.json,英文的最后找ai直接翻译一下给到en.json文件,这样一定程度上节约了时间,并且准确率极高
(否则容易出错-如用cursor直接最后国际化页面里的文本,漏提取or直接中文文本改错,等等问题)

3.swagger接口部分
遇到无厘头但可能相关的接口,问后端!
比如下面这个,登陆的时候勾选同意xxx协议,登陆成功后就要调用这个“用户协议操作记录接口”给到后端,后端记录一下。

(二)理清需求后,调研哪些点可能有阻碍
比如微信小程序权限-系统级别、微信APP级别、微信小程序级别(弄清楚产品要求各情况怎么处理)
比如原后端上传图片接口是否适配微信小程序uploadFile()方式
这些地方都要弄清楚,避免走弯路,尽早将可能遇到的困难问题摆出来,找更有经验的开发or百度or官网寻找解决方案,跟pm明确技术风险,并合理安排时间
避免由于忽视,前期困难点未理清楚导致错误排期and前后端走弯路
一、关于oss图片上传
(一)上传图片本身接口限制
1.微信小程序上传前提
微信小程序本身不直接支持原生的 FormData 对象,但可以通过以下几种方式实现类似 form-data 格式的文件上传功能(这里使用了第一种官方推荐的,其他两种没尝试)


2.具体场景分析
原接口1:APP司机注册
POST /xxx/driver-app/v1/users
表单和上传图片文件都在一起用一个接口(post、formData)上传,2个参数,单文件

这里虽然都是单张图片,但是要分别传人像照和国徽照,且非必传
而uni.uploadFile(obj)的obj中,filePath/files必填,不能为null或者“”
(这里我尝试了用一个固定的下载了线上图片得到的临时地址,可以实现,但并不推荐)

原接口2:APP端运单货物操作: 提货、确认到达
POST /xxx/driver-app/v1/waybills/{id}/actions/loadings
表单和上传图片文件都在一起用一个接口(post、formData)上传,2个参数,多文件数组

(这里swagger写的有问题,事实上是数组,且必填)
这里传的是俩file数组,更不能直接用这个接口了。
后端尝试两种解决:
第一种:oss直传(未采纳)
刚开始后端直接抄的鸿蒙app实现,结果差不多的问题,不支持
鸿蒙前端是用put传的文件,微信小程序不支持的


事实上阿里云分别提供了各种设备的实践demo,各不相同,适配各种环境。
所以以后要注意不能直接鸿蒙抄到微信小程序,不一定适配的。

最终后端研究之后决定不采用直传->前端传文件给阿里云这种形式了(觉得比较麻烦),选择单拎文件上传接口慢慢上传->前端传文件给后端,后端传文件给阿里云
第二种:单独创建上传文件的接口+创建小程序司机注册、货物操作接口(采纳)
上传文件接口
POST /xxx/driver-app/v1/media/upload

注册、货物操作-小程序接口
小程序的传参file/file[]改成了传string/string[]

(二)ios微信小程序照片不显示(安卓正常显示)
1.原因



2.解决方案
看一下后端返回的图片地址是否是http开头的,是的话需要让后端配置一下改成https或者前端处理http->https
A 后端处理(问的ai,并没尝试)-后端适配会更合适
B 前端处理(需确保 Bucket 支持 HTTPS)-本次采纳
oss_url = "http://bucket.oss-cn-hangzhou.aliyuncs.com/image.jpg"
https_url = oss_url.replace("http://", "https://")
(三)微信小程序上传下载文件需配置域名白名单
记得在小程序后台开发管理页配置uploadFile和downloadFile用到的合法域名

二、关于权限
(一)相机和相册权限(仍可能在某些设备如红米等机型出现问题)

1.uniapp封装的组件-uni-file-picker(内置了微信app级别的权限判断)
实现的效果——微信app有权限即能正常使用,无权限的话内置提示
如下图(安卓ios显示不同问题不大,但是安卓红米K80的相机没有弹出首次提醒)



2.自己写微信级别、微信小程序级别的的权限
代码判断什么的自己写,跟定位权限差不多,参考下文。权限从定位改成相机、相册,不用管系统级别权限而已。
(二)定位权限
1.微信小程序权限
uni.authorize(OBJECT) | uni-app官网


uni.openSetting(OBJECT) | uni-app官网

2.系统/微信应用权限


3.代码
流程图

a.先微信小程序级别权限
/** 1.定位
* @param callback
* @param isChange 是否转换坐标系
* @param type 提示语使用哪个
*/
export const getPosition = (isChange: boolean = true) => {
return new Promise((resolve) => {
// 授权获取地理位置
uni.authorize({
scope: 'scope.userLocation',
success() {
getLocation((res: any) => {
resolve(res);
}, isChange)
},
// 小程序定位拒绝
fail() {
uni.showModal({
title: i18n.global.t('locationPermissionTitle'),
content: i18n.global.t('locationPermissionContent'),
confirmText: i18n.global.t('allow'),
cancelText: i18n.global.t('deny'),
confirmColor: '#218BFE',
cancelColor: '#999',
success: res => {
if (res.confirm) {
uni.openSetting({
success(res) {
if (!res.authSetting['scope.userLocation']) {
uni.showModal({
content: i18n.global.t('locationNotEnabled'),
showCancel: false,
confirmText: i18n.global.t('iKnow'),
confirmColor: '#1677FF',
complete: () => {
resolve(undefined);
}
})
} else {
resolve(undefined);
}
}
});
} else if (res.cancel) {
// 不允许
resolve(undefined);
}
},
fail: () => {
resolve(undefined);
}
});
}
});
})
};
b.再系统/微信级别权限+获取定位
/**
* 2.获取定位
*/
export const getLocation = (callback: Function, isChange: boolean = true) => {
uni.getLocation({
type: 'gcj02',
isHighAccuracy: true,
success: function (res) {
let result: any = {};
const {longitude, latitude} = res;
if (isEmpty(longitude) || isEmpty(latitude)) {
const messageError = i18n.global.t('getLocationFailed');
uni.showToast({
title: messageError,
icon: 'none',
duration: 2000,
complete: () => {
// 提示关闭后进行回调操作, 这里callback入参是undefined
setTimeout(callback, 2000);
}
});
} else {
if (isChange) {
result = qqMapTransBMap(longitude, latitude);
} else {
result = {
longitude,
latitude
};
}
callback(result);
}
},
// 一般是微信定位拒绝
fail: (error) => {
const { locationAuthorized } = uni.getSystemInfoSync();
console.error('getLocation error', error);
const tip = !locationAuthorized ? i18n.global.t('wechatLocationDenied') : i18n.global.t('getLocationFailedGeneral');
uni.showToast({
title: tip,
icon: 'none',
duration: 2000,
complete: () => {
// 提示关闭后进行回调操作
setTimeout(callback, 2000);
}
});
}
});
}
三、微信小程序坐标系及地理逆编码调研
(一)坐标系及三方
微信小程序的getLocation可以两种坐标系,国际gps或者国标局gcj02(推荐国标局gcj02,wx.openLoction()要求用gcj02坐标系,且完美适配腾讯/高德地图sdk,百度地图也提供了官方转换方式)
自带没有api实现地理逆编码,要想实现的话需要使用三方sdk/api,比如腾讯/百度/高德地图
微信小程序JavaScript API | 百度地图API SDK





(二)代码
腾讯gcj02百度互转
// 腾讯地图gcj02经纬度转百度地图
export function qqMapTransBMap(lng: number, lat: number) {
let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
let x = lng;
let y = lat;
let z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
let theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
let lngs = z * Math.cos(theta) + 0.0065;
let lats = z * Math.sin(theta) + 0.006;
return {
latitude: lats,
longitude: lngs
}
}
// 百度地图经纬度转腾讯地图gcj02
export function BMapTransQQMap(lng: number, lat: number) {
let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
let x = lng - 0.0065;
let y = lat - 0.006;
let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
let lngs = z * Math.cos(theta);
let lats = z * Math.sin(theta);
return {
latitude: lats,
longitude: lngs
}
}
四、关于input
正则过滤输入,不支持pattern,pattern属性html才有
最后使用的是@input过滤+debounce实现(todo:寻找更好的方法)
五、关于toast
上一个toast会被下一个toast无缝替换(看不出前面的toast,只能看到最后一个toast)
小程序的提示uni.showToas会在页面跳转时消失,导致一闪而过看不清提示的情况--需加setTimeout延迟一下
六、关于防爆
一直以为就调接口需要防爆???
结果拍照页面点击上传也需要???
业务代码里用到了事件总线,由于异步,接口loading也没用,需要手动设置标志位(类似锁)防爆
ps:使用$on,$emit——因为navigateBack不能传参,又想特定时候更新上一页数据

更多推荐




所有评论(0)