博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微信小程序踩坑指南
阅读量:6914 次
发布时间:2019-06-27

本文共 10305 字,大约阅读时间需要 34 分钟。

微信小程序降(小)妖伏(小)魔篇

开发就是一个西行取经的过程,期间不是一帆风顺,不定会遇到什么鬼。

最近开发一个简单的每日答题签到小程序,期间遇到一些始料未及的坑记录一下,避免日后重复踩坑。本文针对初入小程序的小白。:)

可能会有更好的解决方案,欢迎指正。

多张gif图预警,大概20M ?

第一难: scroll-view标签对dispay:flex无效

想要实现一个横向滚动的日历,很自然的想到scroll-view组件,于是洋洋洒洒的写下几行代码:

demo.wxml

{
{item}}
复制代码

demo.scss(为了写着方便,请自行转换成wxss语法,下同)

page {  width: 100%;  height: 100%;  background: #17448E;}.scroll-view-demo {  display: flex;  flex-direction: row;  .item {    width: 80rpx;    height: 80rpx;    border: solid 1px #fff;    display: flex;    color: #fff;    font-size: 36rpx;    justify-content: center;    align-items: center;    border-radius: 40rpx;    margin-left: 50rpx;  }}复制代码

搓搓手,看看效果

尴尬,说好的横向滚动呢,明明flex-direction: row;写的清清楚楚明明白白。。

既然scroll-viewflex不友好,那我在子元素上再包裹一层view组件应该万事大吉了吧,于是:

demo.wxml

{
{item}}
复制代码

demo.scss

.scroll-view-demo {  .item-container {    display: flex;    flex-direction: row;    .item {      width: 80rpx;      height: 80rpx;      border: solid 1px #fff;      display: flex;      color: #fff;      font-size: 36rpx;      justify-content: center;      align-items: center;      border-radius: 40rpx;      margin-left: 50rpx;    }  }}复制代码

看看效果:

然鹅。。好像不是那么回事,子元素怎么就被挤成胶囊了。。 仔细研究一番,需要给.item-container加上固定的width才行,甚是麻烦。

简单点,开发的方式简单点,既然scroll-viewflex如此高冷,那就换一种方式:

demo.wxml

{
{item}}
复制代码

demo.scss

.scroll-view-demo {  width: 100%;  white-space: nowrap;  .item {    width: 80rpx;    height: 80rpx;    line-height: 80rpx;    text-align: center;    border: solid 1px #fff;    display: inline-block;    color: #fff;    font-size: 36rpx;    border-radius: 40rpx;    margin-left: 50rpx;  }复制代码

效果:

两个字,接近完美?

不过,在手机上浏览scroll-view会有一个滚动条,很丑有木有

于是挑灯夜读翻阅资料找到解决方法:

app.css

/*隐藏scroll-view滚动条*/::-webkit-scrollbar{  width: 0;  height: 0;  color: transparent;}复制代码

这下妥妥的了,

年轻人切记,scroll-view 尽量不用flex

第二难: scroll-view 设置scroll-left无效问题

以为scroll-view踩完一个坑就结束了么,图森破图样。

想给scroll-view在页面loading结束后滚动到某一个位置, 很简单,闭着眼写代码:

demo.wxml

{
{item}}
复制代码

demo.js

Page({	data: {		scrollLeft: 100,		list: []	},	onLoad(){		setTimeout(()=>{			//假装异步获取数据			this.setData({				list: [1,2,3,4,5,6,7,8]			});		},1000);	}})复制代码

看效果,发现scroll-view带在原地纹丝不动。惆怅~

let me see see 代码稍作改动:

demo.js

Page({	data: {		scrollLeft: 0,		list: []	},	onLoad(){		setTimeout(()=>{			//假装异步获取数据			this.setData({				list: [1,2,3,4,5,6,7,8],				scrollLeft: 100			});		},1000);	}})复制代码

perfect 果然达到了预期,细想原因:

  • 一般在页面加载时我们会请求数据,并渲染列表, 但是我们在标签或者data中设置的scroll-left值会在数据渲染前赋值.
  • 此时的scroll-view中还是空的,所以scroll-left不会生效. 我们应该在数据渲染到scroll-view中以后,再同步scroll-left的值

第三难: button自定义样式,无法去掉默认样式

想写一个自定义样式的按钮,so easy,给我一秒写出来:

demo.wxml

超新脱俗的按钮
复制代码

demo.scss

button,.button {  width: 500rpx;  height: 88rpx;  display: flex;  align-items: center;  justify-content: center;  font-size: 32rpx;  background: #FE7437;  color: #fff;  border-radius: 44rpx;  margin: 20rpx auto;}复制代码

效果:

猛一看,感觉不能再完美了,定睛一看,怎么觉得button组件写出来的按钮不是那么纯洁,有阴影。

很自然的再加行代码:

demo.scss

border: none;复制代码

事情并没有那么简单,阴影依然噩梦般存在。 有困难,找百度,果不其然大神们的奇技淫巧顺利解决,贴上完整代码:

demo.scss

button,.button {  width: 500rpx;  height: 88rpx;  display: flex;  align-items: center;  justify-content: center;  font-size: 32rpx;  background: #FE7437;  color: #fff;  border-radius: 44rpx;  margin: 20rpx auto;  &::after{    border-radius: 0;    border: none;  }}复制代码

效果:

简直两个按钮一模一样。

第四难 让人伤神的input组件

小程序开发免不了要有登录页面,于是就离不开input组件,代码就不贴了,常规操作,直接上图。

看图很容易发现几个问题:

  1. 切换input时 文字会闪动
  2. 切换下一个input时 需要多次才能获取到焦点,弹出键盘。
  3. 如果在不同的手机上看,会发现密码框的黑点大小也不一致

针对第一个问题,百度谷歌挖地三尺也木有找到好的解决办法(可能是挖的不够深 :() 第二个问题,既然不能自主获取焦点,那我们结合官方文档助它一臂之力:

demo.wxml

复制代码

demo.scss

...复制代码

demo.js

Page({    data: {        username: '',        password: '',        selectName: true,        selectPwd: false,    },    getUsername(e){        //获取用户名        this.setData({            username: e.detail.value,        });    },    getPassword(e){        //获取密码        this.setData({            password: e.detail.value,        })    },    handleName(){        this.setData({            selectName: true,            selectPwd: false,        })    },    handlePwd(){        this.setData({            selectName: false,            selectPwd: true,        })    }});复制代码

看看效果:

看着像是好多了 ? 思考: 若文本框不止两个,怎么写才更优雅,另,没有看在不同手机上的表现。

第三个关于密码黑点大小的问题 我也木有良策 +_+

以下是网上大佬们关于input组件bug的总结:

  • placeholder 文字与 input 的值重叠 暂无解决方法

  • 获取焦点 和 失去焦点 时,光标和文字跳动 暂无解决方法

  • input 设置为居中对齐时,光标会出现在奇怪的位置 暂无解决方法

  • bindconfirm 事件在失去焦点时也会触发,类似于 blur 暂无解决方法

  • input 做动画时,如果是获取焦点状态,会失效 暂无解决方案,因为 input 在获取焦点时是native 组件,失去焦点后改回 web 组件

  • typeidcard, digit 时并不是调用数字键盘 暂无解决方案,目前起作用的只有 number

  • input聚焦期间,不能做css动画,否则input中的placeholder会错位,如果动画和聚焦都想要的话,那么可以在动画完成之后,再设置聚焦

看看微信官方社区的吐槽,如果你也被坑了,去给助个攻吧

第五难 getPhoneNumber获取用户手机号解密报错问题

小程序登录时我们可以利用微信获取手机号快捷登录,根据文档我们很容易写一套登录流程:

demo.wmxl

复制代码

demo.js

Page({	...	async getPhoneNumber(e) {		if(!e.detail.iv){            //被拒绝授权            return;        }                let code = '';                 /*    	  * 别慌,wxPromise.login()其实就是wx的api被promise化,参考 **转转**代码    	  * https://github.com/zhuanzhuanfe/fancy-mini/blob/master/src/wxPromise.js    	  */    	  const res = await wxPromise.login();    	  code = res.code;    	      	  if(!code){    	  	console.error(`调用 wx.login 失败`, err);            return util.toast('微信登录失败');    	  }                try{        	//server端微信登录接口            const result = await service.passport.wxLogin({                data: {                    code: code,                    iv: e.detail.iv,                    encryptedData:  e.detail.encryptedData                }            });            const res = result.data;            if (res.status === 0) {                // 登录成功               	...            }else {                ...            }        }catch(err){           ...        }        	}	...});复制代码

server.js

async wxLoginAction(){	//微信登录        const {ctx} = this;        const body = ctx.request.body;        //请求微信接口 https://api.weixin.qq.com/sns/jscode2session        const result = await this.callService('wxApplet.code2Session', {            appid: ***,            secret: ***,            js_code: body.code,            grant_type: 'authorization_code'        });                if(result.status == 0){            let sessionKey = result.data.session_key;            let encryptedData = body.encryptedData;            let iv = body.iv;            //解密获取手机号 (解密库小程序文档有对应的源码)            let pc = new WXBizDataCrypt(appid, sessionKey);            let mobile = pc.decryptData(encryptedData, iv).phoneNumber;                        //解密成功 生成登录态等操作            ...                        return this.json({            	status: 0,            	message: 'ok',            	data: mobile            });                    }else {        	....        }}复制代码

搓搓手,看效果:

竟然首次登录的时候有报错,以后再次登录却一切正常。

看server端报错日志,如下:

Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt复制代码

这条error信息是从WXBizDataCrypt解密失败时抛出来的。

查看文档,看button的官方文档Tips中有这一条:

在bindgetphonenumber 等返回加密信息的回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。建议开发者提前进行 login;或者在回调中先使用 checkSession 进行登录态检查,避免 login 刷新登录态。

另外,查看网上大神的解决方案,其中有一条是这样说的:

纳尼,点击按钮之前就要调用login,于是将信将疑的再次修改代码:

demo.js

Page({	data: {		code: ''	},	async onLoad(options){		try {            const res = await wxPromise.login();            this.setData({                code: res.code            })        }catch (err){            this.setData({                code: ''            })        }	},	async getPhoneNumber(e) {		if(!e.detail.iv){            //被拒绝授权            return;        }        let code = this.data.code;        if(!code){    	  	console.error(`调用 wx.login 失败`, err);            return util.toast('微信登录失败');    	  }                try{        	//server端微信登录接口            const result = await service.passport.wxLogin({                data: {                    code: code,                    iv: e.detail.iv,                    encryptedData:  e.detail.encryptedData                }            });            const res = result.data;            if (res.status === 0) {                // 登录成功               	...            }else {                ...            }        }catch(err){           ...        }	}});复制代码

修改完毕,经过测试,首次登录果然很顺利就成功了,但是又出现了一个幺蛾子,再次登录就又又又报错:

error: code is used复制代码

这个报错就很好理解了,稍稍修改一下代码:

demo.js

Page({	data: {		code: ''	},	async onLoad(options){		try {            const res = await wxPromise.login();            this.setData({                code: res.code            })        }catch (err){            this.setData({                code: ''            })        }	},	async getPhoneNumber(e) {		if(!e.detail.iv){            //被拒绝授权            return;        }        let code = this.data.code;                if (!code) {            //防止code失效            try{                const res = await wxPromise.login();                code = res.code;            }catch(err){                console.error(`调用 wx.login 失败`, err);                return util.toast('微信登录失败');            }        }                try{        	//server端微信登录接口            const result = await service.passport.wxLogin({                data: {                    code: code,                    iv: e.detail.iv,                    encryptedData:  e.detail.encryptedData                }            });            const res = result.data;                        this.setData({                //用过的code需要清空,重新获取                code: ''            });                        if (res.status === 0) {                // 登录成功               	...            }else {                ...            }        }catch(err){           ...        }	}});复制代码

泪流满面,自我测试,确实经得起组织考验,完美解决。(也可能测试的不够透彻,如果还有报错,或者更好的解决方案,欢迎打脸T T)

第六难 刷新页面图片加载时变形问题

image组件开发时特别常见,要写一个宽度固定,高度自适应代码也很简单:

demo.wxml

复制代码

看着很简单,感觉稳稳地,但是刷新页面时会有中见鬼的赶脚,话不多说上图:

仔细看似乎有鬼影掠过。。。 加载时图片被拉扯变形,?

其实解决方法也很简单:

demo.scss

image {	height: auto;}复制代码

对,就是这么简单,就完美解决。?

以上。

结束

开发是一个漫长的过程,前面未知的坑还很多。火来水挡水来土掩,填的坑越多,路会越平坦,再攒一波坑,等下次更新。

最后插播一条广告,经过一天多次被拒后,小程序终于审核通过了(感谢各种TV T T),欢迎体验吐槽


参考文章:

小程序里的登录态处理,主要参考以下文章(具体实现省略):

转载于:https://juejin.im/post/5cf0c03df265da1b7b3170b6

你可能感兴趣的文章
浮动布局和清除浮动
查看>>
关于slice()、substr()、substring()方法
查看>>
['1','2','3'].map(parseInt)的返回值是什么?
查看>>
引入iconfont图标-微信小程序
查看>>
权限(适用于初学者)
查看>>
startService过程
查看>>
内容创业转舵
查看>>
leetcode 120 三角形最小路径和
查看>>
圣杯布局进阶版-flex布局实现
查看>>
《速度与激情》范迪塞尔代言!雅迪和高端“死磕”到底
查看>>
LLDB 知多少
查看>>
淘宝、网易移动端 px 转换 rem 原理,Vue-cli 实现 px 转换 rem
查看>>
js监听gif停止 libgif-js Gif 操作(开始,暂停,移动帧...) 功能强大
查看>>
java并发编程 • 核心 • 状态管理
查看>>
[译] 从没有人告诉过我的 CSS 小知识
查看>>
这个乐趣,支付宝落地实践
查看>>
Golang 1.x版本泛型编程
查看>>
武汉区块链软件技术公司:区块链应用为何成为现实版的“海市蜃楼”
查看>>
关于制作pod时使用xib等资源文件的问题
查看>>
《代码大全》读书笔记-构建的前期
查看>>