微信小程序开发常见问题

场景一:首页增加下拉刷新功能无效?

经过各种尝试 问题定位到了是因为 在 scroll-view 中使用了 onPullDownRefresh,最后通过改首页的代码结构达到了预期结果

结论:
在滚动 scroll-view 时会阻止页面回弹,所以在 scroll-view 中滚动,是无法触发 onPullDownRefresh

如果非要在 scroll-view 使用下拉刷新,官方给出的解决方案是监听页面的滚动事件 bindscroll 厄.. 也是一种方法 只不过我的更粗鲁一些

其他需要注意的:

  • 不要在 scroll-view 中使用 textareamapcanvasvideo 组件
  • 目前只验证过 textarea 暂且放到场景二吧
  • scroll-into-view 的优先级高于 scroll-top

场景二:无法在 scroll-view 中使用 textarea?

这是个只有在真机上才会出现的 bug

刚开始以为是不能在某些特定的组件内使用textarea 几番尝试 发现是因为 textarea组件与其他组件的层级关系 后来发现 文档在最下方用最小号的字体给标注出来了已经!吐血

结论:
textarea组件是由客户端创建的原生组件,他的层级是最高的,在实际项目中 要保证本页面中 无
弹层之类一切可能会覆盖到页面的鬼。

其他需要注意的:

  • 不要在 scroll-view 中使用 textarea 组件。
  • css 动画对 textarea 组件无效
  • textarea 的 blur 事件会晚于页面上的 tap 事件,如果需要在 button 的点击事件获取 textarea,可以使用 form 的 bindsubmit。
  • 官方遗留 bug: textarea 在列表渲染时,新增加的 textarea 在自动聚焦时的位置计算错误。

    场景三:textarea 的 placeholder 不固定的问题

当把textarea放到一个 position:fixed 中的元素中时,会发现这个textarea也会跟着固定位置,但是textarea的 placeholder 内容不会固定,当滚动页面时,placeholder 的内容会跟着滚动

解决方式:textarea组件增加属性 fixed

结论:踩坑大法好

场景四:微信小程序的兼容问题

wx.request() 返回的状态码 res.statusCode 的值 在 IOS 下是 init 型的数据 但是在 Android 6.0.1 上却是 String 型数据
要特别注意判断状态码的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
X
wx.request({
url: 'http://api.example.com',
success: function (res) {
if (res.statusCode === 200) {
// success
} else {
// server failure
}
}
})
像这样使用 === 就错了 不要判断类型
使用 ==即可

小程序的 WXML 没有 HTML 的宽容度​那么高,单标签必需是 /> 结尾的 不然会报错。

场景五:小程序版本的兼容问题

无论用哪个组件 必须时刻注意当前兼容的版本 做低版本兼容

1
2
3
4
5
6
7
8
 wx.openBluetoothAdapter()
} else {
// 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
wx.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}

Fundebug 能够实时监测小程序,捕获小程序 Bug,然后反馈给开发者
Fundebug

场景六:小程序版本的兼容问题

绑定事件的时候,当两个方法重名时,后面的方法会覆盖前面的方法,并且 IDE 不报错

场景七:image

小程序的 image 与 HTML5 的 img 最大的区别在于:
小程序的 image 是按照 background-image 来实现的。
默认 image 的高宽是 320*240。必须通过样式定义去覆盖这个默认高宽,auto 在这里不生效。
开发者说这样设置的原因是:如果设置 auto ,页面布局会因为图片加载的过程有一个闪的现象(例如高度从 0 到 height ),所以要求一定要设置一个宽度和高度。

图片包括三种缩放模式 scaleToFill、aspectFit、aspectFill 和 9 种裁剪模式,三种缩放模式的实现原理对应如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
scaleToFill{

background-size:100% 100%;//不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素

}

aspectFit{

background-size:contain;//保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。

}

aspectFill{

background-size:cover;//保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。

}

场景八:navigator

navigator 支持相对路径和绝对路径的跳转,默认是打开新页面,当前页面打开需要加 redirect;
navigator 仅支持 5 级页面的跳转;
navigator 不可跳转到小程序外的链接地址;

1
<navigator class="navigator" redirect  url="../login/index" >登录页</navigator>

在小程序开发工具里,默认打开新页面,工具左上角有返回按钮。加上 redirect,当前页打开,不出现返回按钮。

场景八:大胆使用 flex 布局

在做传统 H5 的时候,为了兼容各种低端设备的机型,通常不太敢轻易尝试 flex,但在小程序里就可以大胆的使用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.media {

display: flex;

justify-content:center;
align-items:center;
}

.media .content {

flex: 1;

}

场景八:大胆使用 flex 布局

在做传统 H5 的时候,为了兼容各种低端设备的机型,通常不太敢轻易尝试 flex,但在小程序里就可以大胆的使用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.media {

display: flex;

justify-content:center;
align-items:center;
}

.media .content {

flex: 1;

}

场景八:页面最后一个 view 组件 设置 margin-bottom 属性 IOS 机型 失效的问题

解决方式:当前 view 当前组件下加一个同级 view

1
2
3
4
5
6
7
8
9
10
11
12
wxml
<view>这是个按钮</view>
<view class="marginB"></view>

css

.marginB{
height: 0rpx;
font-size: 0rpx;
}


场景九:实现长按保存图片 短按图片隐藏

现有问题 用户体验不佳 长按需要抬起才能弹出 sheetAction 菜单

理想状态下是长按开始计时 350 秒之后自动弹操作菜单

利用 bindtouchstartbindtouchend 事件结合 bindtap 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

问题代码一

WXML

<view bindtouchstart="mytouchstart" bindtouchend="mytouchend" bindtap="editAddress" >

JS

editAddress: function (event) {
let that = this;
//触摸时间距离页面打开的毫秒数
var touchTime = that.data.touch_end - that.data.touch_start;
console.log(touchTime);
//如果按下时间大于350为长按
if (touchTime > 350) {

//TODO..

} else {

//TODO..

}
},
//按下事件开始
mytouchstart: function (e) {
let that = this;
that.setData({
touch_start: e.timeStamp
})
console.log(e.timeStamp + '- touch-start')
},
//按下事件结束
mytouchend: function (e) {
let that = this;
that.setData({
touch_end: e.timeStamp
})
console.log(e.timeStamp + '- touch-end')
}


改进

小程序的事件触发顺序

单击 touchstart → touchend → tap
双击 touchstart → touchend → tap → touchstart → touchend → tap
长按 touchstart → longtap → touchend → tap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
问题代码二

wxml

<view bindlongtap="longPress" bindtap="tapFun" style="width: 100%;height:100%" mode="scaleToFill" src="{{img_url}}"></view>

js

longPress(e){
var that = this;
console.log('你点击了长按时间',e)
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope
wx.getSetting({
success(res) {
console.log('222222222222222222')
if (!res['scope.writePhotosAlbum']) {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success() {
// 调起操作菜单
console.log('33333333333333333333')
console.log('wx.showActionSheet()',wx.showActionSheet)
wx.showActionSheet({
itemList: ['保存到本地'],
success: function(res) {
console.log('操作菜单弹出成功','第'+res.tapIndex+'个操作菜单弹出成功')
// 下载文件资源到本地。客户端直接发起一个 HTTP GET 请求,返回文件的本地临时路径。
if(res.tapIndex ==0){
console.log('wx.downloadFile',wx.downloadFile)
wx.downloadFile({
url: that.data.img_url, //仅为示例,并非真实的资源
success: function(res) {
wx.playVoice({
filePath: res.tempFilePath
});
console.log('wx.playVoice()',wx.playVoice)
console.log('将图片先保存到本地--res.tempFilePath',res.tempFilePath);
// 用户已经同意小程序使用功能,后续调用 wx.startRecord 接口不会弹窗询问
console.log('wx.saveImageToPhotosAlbum()',wx.saveImageToPhotosAlbum)
wx.saveImageToPhotosAlbum({
filePath:res.tempFilePath,
success(res) {
wx.showToast({
title: '保存成功',
icon: 'success'
});
setTimeout(function(){
wx.hideToast();
},3000)
},
fail(res){
wx.showToast({
title: '保存失败',
icon: 'success'
});
setTimeout(function(){
wx.hideToast();
},3000)
}
})

}
})
}
},
fail: function(res) {
console.log('操作菜单弹出失败',res.tapIndex)
}
})


}
})
}
}
})
},


tapFun: function(event) {
that.setData({
qrShow:false
})
}


很显然 这也是有问题的

因为事件机制。总会触发 tap事件 表现形式比 问题一还难以接受

好了,结合前两种 解决办法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
WXml

<image wx:if="{{img_url !=''}}" bindlongtap="editAddress1" bindtouchstart="mytouchstart" bindtouchend="mytouchend" style="width: 100%;height:100%" mode="scaleToFill" src="{{img_url}}"></image>


js

//按下事件开始
mytouchstart:function(e){
let that = this;
that.setData({
touch_start: e.timeStamp
})
console.log(e.timeStamp + '- touch-start')
},

//按下事件结束
mytouchend:function(e){
let that = this;
that.setData({
touch_end: e.timeStamp
})
console.log(e.timeStamp + '- touch-end')
that.editAddress(e);
},

// 判断是长按操作还是短按操作
editAddress: function(event) {
var that = this;
if(that.data.touch_end - that.data.touch_start < 350){
that.setData({
qrShow:false
})
}


},

editAddress1(e){} // 同问题二 longPress()

场景十:第二次扫码进入小程序的缓存问题