全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-07-15_uniapp开发微信小程序,我踩了大家都会踩的坑

您的位置:首页 >> 新闻 >> 行业资讯

uniapp开发微信小程序,我踩了大家都会踩的坑 关注公众号,“技术干货”及时达!?最近使用uniapp开发了一个微信小程序(本项目技术栈是uniapp + vue3 + ts,用了最近比较火的模板unibest。),踩了一些大家普遍都会踩的坑,下面做一些总结。文章多处「引用到权威官方内容」和一些「比较可靠的文章」。如有错误,欢迎指正。 ?1. 使用微信昵称填写能力遇到的问题自 2022 年 10 月 25 日 24 时后,wx.getUserProfile 和 wx.getUserInfo的接口被收回,要想获取微信的昵称头像需要使用微信的头像昵称填写能力。 我们的设计稿中「没有编辑确认按钮」,所以应该「失焦后」就「调用」后端的变更昵称接口: 但是失焦之后,微信会对昵称内容「做合规性校验」,导致「失焦后不能立马获取到输入的内容」: uv-inputv-model="form.name"type="nickname"placeholder="请输入内容"@blur="handleSubmit"/uv-input asyncfunctionhandleSubmit(){ console.log('form.value.name',form.value.name)//测试用户001 console.log('rawName',rawName)//测试用户001 if(form.value.name===rawName) return //... } 因此最开始的想法是「等待」校验结束: asyncfunctionhandleSubmit(){ //微信会对type="nickname"的输入框失焦时进行昵称违规校验,这个校验是异步的,所以需要等待一下 awaitnewPromise((resolve)=setTimeout(resolve,0)) console.log('form.value.name',form.value.name)//Jude console.log('rawName',rawName)//测试用户001 if(form.value.name===rawName){ return } //... } 但如果真的输入了违规昵称,微信将「自动清空」输入框内容,而「在此之前」我的提交「请求已经发送」: 因此需要用到官方新加的一个回调事件bindnicknamereview(文档): uv-inputv-model="form.name"type="nickname"placeholder="请输入内容"@nicknamereview="handleSubmit"/uv-input functiononNickNameReview(e){ console.log('onNickNameReview',e) if(e.detail.pass){ //校验通过 handleSubmit() }else{ form.value.name=rawName } } 但发现 uv-ui 并没有提供这个事件,还是没有生效,只能改node_modules的uv-input源码,并给uv-ui提个pr: 2. 自定义导航栏原生导航栏配置方面有很多限制,比如不允许修改字体大小等。所以有的时候需要自定义导航栏。 「首先注意,webview的页面无法自定义导航栏!」 所以:「导航栏高度 = 状态栏到胶囊的间距(胶囊上坐标位置-状态栏高度) * 2 + 胶囊高度 + 状态栏高度」 「第一步」:配置当前页面的json文件 //pages.json {navigationStyle:"custom"} 「第二步」:获取状态栏和导航栏高度,只需要获取一次即可,获取到可以放到pinia里 //自定义导航栏 conststatusBarHeight=ref(0) constnavBarHeight=ref(0) statusBarHeight.value=uni.getSystemInfoSync().statusBarHeight letmenuButtonInfo=uni.getMenuButtonBoundingClientRect() navBarHeight.value=menuButtonInfo.height+(menuButtonInfo.top-statusBarHeight.value)*2 「第三步」:自定义导航栏 viewclass="nav-bar" !--状态栏占位-- view:style="{height:statusBarHeight+'px'}"/view !--真正的导航栏内容,请按照自己的需求自行定义-- viewclass="nav-bar-content"style="font-size:34rpx;":style="{height:navBarHeight+'px'}"导航栏标题/view /view 「问题」:微信小程序原生导航栏会根据微信设置(字体大小,是否开启深色模式)等变化,深色模式是页面是可以获取到的,但字体大小等目前没有开放接口,所以无法根据微信设置动态变化。 3. 自定义tabbar由于原生底部tabbar的局限性,未能满足产品需求,所以需要自定义tabbar。 「首先」,自定义tabbar的第一步配置pages.json: //pages.json tabBar:{ custom:true, //... }, 「然后」,我们只需要「在项目根目录(src)创建custom-tab-bar目录,uniapp编译器会直接它拷贝到小程序中:」 !--src/custom-tab-bar/index.wxml-- viewclass="tab-bar" viewclass="tab-bar-border"/view viewwx:for="{{list}}"wx:key="index"class="tab-bar-item"data-path="{{item.pagePath}}"data-index="{{index}}"bindtap="switchTab" imageclass="tab-bar-item-img"src="{{selected===index?item.selectedIconPath:item.iconPath}}"/image viewclass="tab-bar-item-text"style="color:{{selected===index?selectedColor:color}}"{{item.text}}/view /view /view //src/custom-tab-bar/index.js Component({ data:{ selected:0, color:"#8d939f", selectedColor:"#e3eaf9", list:[{ pagePath:"/pages/index/index", iconPath:"../static/tabbar/home01.png", selectedIconPath:"../static/tabbar/home02.png", text:"首页" },{ pagePath:"/pages/my/my", iconPath:"../static/tabbar/user01.png", selectedIconPath:"../static/tabbar/user02.png", text:"我的" }] }, attached(){ }, methods:{ switchTab(e){ constdata=e.currentTarget.dataset consturl=data.path wx.switchTab({url}) this.setData({ selected:data.index }) } } }) //src/custom-tab-bar/index.json { "component":true } // src/custom-tab-bar/index.wxss .tab-bar { position: fixed; bottom: calc(16rpx + env(safe-area-inset-bottom)); left: 0; right: 0; height: 100rpx; background: linear-gradient(180deg, rgba(13, 15, 26, 0.95) 0%, rgba(42, 50, 76, 0.95) 100%); box-shadow: 0rpx 4rpx 16rpx 0px rgba(0, 0, 0, 0.12); display: flex; width: calc(100% - 2 * 36rpx); border-radius: 36rpx; margin: 0 auto; } .tab-bar-item { flex: 1; text-align: center; display: flex; justify-content: center; align-items: center; flex-direction: column; } .tab-bar-item .tab-bar-item-img { width: 32rpx; height: 32rpx; } .tab-bar-item .tab-bar-item-text { margin-top: 10rpx; font-size: 20rpx; } 最后,「关键坑」注意:每个tab页都有自己的tabbar实例: 因此需要每个tab页渲染时设置一下自定义tabbar组件的 activeIndex(我这里变量名是selected): 如果是原生小程序开发像官网那样写就好,如果是uniapp开发,需要: onShow(()={ constcurrentPage=getCurrentPages()[0];//获取当前页面实例 constcurrentTabBar=currentPage?.getTabBar?.(); //设置当前tab页的下标index currentTabBar?.setData({selected:0 }) 效果: 4. IOS适配安全距离当用户使用圆形设备访问页面时,就存在“安全区域”和“安全距离”的概念。安全区域指的是一个可视窗口范围,处于安全区域的内容不受圆角(corners)、齐刘海(sensor housing)、小黑条(Home Indicator)的影响。 上图来自designing-websites-for-iphone-x 「uniapp适配:」 uniapp适配安全距离有三个方法: a. manifest.json配置安全距离//manifest.json { "app-plus":{ "safearea":{//可选,JSON对象,安全区域配置 "background":"#RRGGBB",//可选,字符串类型,#RRGGBB格式,安全区域背景颜色 "backgroundDark":"#RRGGBB",//可选,字符串类型,#RRGGBB格式,暗黑模式安全区域背景颜色 "bottom":{//可选,JSON对象,底部安全区域配置 "offset":"auto"//可选,字符串类型,安全区域偏移值,可取值auto、none }, "left":{//可选,JSON对象,左侧安全区域配置 "offset":"none"//可选,字符串类型,安全区域偏移值,可取值auto、none }, "right":{//可选,JSON对象,左侧安全区域配置 "offset":"none"//可选,字符串类型,安全区域偏移值,可取值auto、none } }, } } 「问题:」 这种方式显然***不够灵活***,它设置的是单独的背景色,如果需要下方一个区域是背景图,延伸到底部安全区就满足不了了。 所以,我是将以上的配置设置成none,然后手动适配页面的安全距离: b. js获取安全距离letapp=uni.getSystemInfoSync() app.statusBarHeight//手机状态栏的高度 app.bottom//底部安全距离 c. 使用苹果官方推出的css函数env()、constant()适配padding-bottom:constant(safe-area-inset-bottom);/*兼容IOS11.2*/ padding-bottom:env(safe-area-inset-bottom);/*兼容IOS11.2*/ 「注意:」 constant和env不能调换位置 可以配合calc使用: padding-bottom:calc(constant(safe-area-inset-bottom)+20rpx);/*兼容IOS11.2*/ padding-bottom:calc(env(safe-area-inset-bottom)+20rpx);/*兼容IOS11.2*/ 「h5适配」 网页适配安全距离的前提是需要将meta name="viewport"标签设置viewport-fit:cover;: metaname='viewport'content='initial-scale=1,viewport-fit=cover' 这是MDN上关于viewport-fit的解释: image.png直观一点就是: 上图来自移动端安全区域适配方案 然后再使用env和constant padding-bottom:constant(safe-area-inset-bottom);/*兼容IOS11.2*/ padding-bottom:env(safe-area-inset-bottom);/*兼容IOS11.2*/ 5. 列表滚动相关问题列表滚动如果使用overflow: auto; 在「首次下拉」时(即使触控点在列表内)也「会使整个页面下拉」: 「解决这个问题只需要将内容使用 scroll-view 包裹即可:」 scroll-viewscroll-yclass="max-h-[800rpx]overflow-auto"/scroll-view 「下拉刷新将列表滚动到顶部:」 小程序默认使用webview渲染,如果需要Skyline渲染引擎需要配置,而srcoll-view标签在webview中有个独有的属性enhanced,启用后可通过ScrollViewContext操作 scroll-view: scroll-viewid="scrollview":enhanced="true"scroll-yclass="max-h-[800rpx]overflow-auto"/scroll-view /**将scrollview滚动到顶部*/ functionscrollToTop(id:string){ wx.createSelectorQuery() .select(id) .node() .exec((res)={ constscrollView=res[0].node; scrollView.scrollTo({ top:0, animated:true }) } onPullDownRefresh(async()={ console.log('下拉刷新') try{ awaitfetchList() }catch(error){ console.log(error) }finally{ uni.stopPullDownRefresh() scrollToTop('#scrollview') } }) 6. 配置小程序用户隐私保护指引文档:小程序隐私协议开发指南 什么时候要配置:但凡你的小程序「用到」上图中「任何一种用户信息」就得配置,否则可能小程序审核不通过,或者以前通过了后面不知道什么时候就会被下架了。 配置的是什么:配置的是将来你的程序打开让用户确认授权的「隐私协议内容」。 如何配置:登录微信公众平台 - 设置 - 服务内容声明 - 用户隐私保护指引 - 修改 隐私弹框触发的流程是什么:程序调用隐私相关接口 —— 微信判断该接口「是否」需要隐私授权 —— 如果「需要」隐私授权「且」开发者没有对其响应(注册onNeedPrivacyAuthorization的监听事件)「则」主动弹出官方弹框(此时隐私相关接口调用处于pending状态,如果用户拒绝将会报{"errMsg":" getLocation:fail privacy permission is not authorized", "errno":104})。 代码逻辑:配置并「等待审核通过」后,进行以下步骤: 「1. 配置 __usePrivacyCheck__: true」 尽管官方文档说明2023年10月17日之后无论是否配置改字段,隐私相关功能都会启用,但是实际尝试后发现还是得「配置上才生效」。 //manifest.config.ts 'mp-weixin':{ __usePrivacyCheck__:true }, 「2. 自定义隐私弹框组件」 尽管官方提供了官方隐私弹框组件,但是真机上没有生效,于是还是使用了自定义隐私弹框。 我是直接在插件市场找了一个下载量最多的插件,兼容vue2和vue3。 在小程序对应的页面: WsWxPrivacyid="privacy-popup"@agree="onAgree"@disagree="onDisAgree"/WsWxPrivacy functiononAgree(){} functiononDisAgree(){} tip: 这部分逻辑相对于业务是「几乎没有耦合」的,甚至如果没有特殊需求agree和disagree事件都不用写。如果将来官方主动弹框没问题了,那这个逻辑可以直接删掉。 「3. 业务代码」 举个例子,我这里隐私相关接口是uni.getLocation获取用户地理位置。 functionhandleCheckLocation(){ returnnewPromise((resolve,reject)={ uni.getLocation({ type:'gcj02', success:async(res)={ console.log('当前位置:',res) try{ letr=awaitcheckLocation({ lon:res.longitude.toString(), lat:res.latitude.toString(), }) //... resolve('success') }catch(error){ reject(error) } }, fail:(error)={ console.log('获取位置失败:',error) reject(error) } }) }) } 以上代码,在调用uni.getLocation时,微信自动「发起位置授权」,发起位置授权「之前」又会自动发起「隐私授权」。到此,这一流程是ok的。但是,「如果用户拒绝了隐私授权,或者拒绝了位置授权」,该怎么办? 「如果拒绝了隐私授权」,下次调用隐私相关接口时还会再次弹出隐私授权弹框。 「如果拒绝了位置授权」,下次调用就不会弹出位置授权弹框,但可以通过uni.getSetting来判断用户是否拒绝过,再通过wx.openSetting让用户打开设置界面手动开启授权。代码如下: functiongetLocationSetting(){ uni.getSetting({ success:(res)={ console.log('获取设置:',res) if(res.authSetting['scope.userLocation']){ //已经授权,可以直接调用getLocation获取位置 handleCheckLocation() }elseif(res.authSetting['scope.userLocation']===false){ //用户已拒绝授权,引导用户到设置页面开启 wx.showModal({ title:'您未开启地理位置授权', content:'请在设置中开启授权', success:res={ if(res.confirm){ wx.openSetting({ success(settingRes){ if(settingRes.authSetting['scope.userLocation']){ //用户打开了授权,再次获取地理位置 handleCheckLocation() } } }) } } }) }else{ //首次使用功能,请求授权 uni.authorize({ scope:'scope.userLocation', success(){ handleCheckLocation() } }) } } }) } 当然你也可以「封装」一下: functiongetSetting(scopeName:string,cb:()=any){ uni.getSetting({ success:(res)={ console.log('获取设置:',res) if(res.authSetting[scopeName]){ //已经授权,可以直接调用 cb() }elseif(res.authSetting[scopeName]===false){ //用户已拒绝授权,引导用户到设置页面开启 wx.showModal({ title:'您未开启相关授权', content:'请在设置中开启授权', success:res={ if(res.confirm){ wx.openSetting({ success(settingRes){ if(settingRes.authSetting[scopeName]){ //用户打开了授权,再次获取地理位置 cb() } } }) } } }) }else{ //首次使用功能,请求授权 uni.authorize({ scope:scopeName, success(){ cb() } }) } } }) } 这样,整个隐私协议指引流程就完整了。 关注公众号,“技术干货”及时达! 阅读原文

上一篇:2024-10-09_假期去了Haus Nowhere,算是逛了个景点吗丨品牌兔子洞 下一篇:2025-03-26_用DeepSeek3分钟搞定专业海报,AI时代的设计新玩法

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价