小程序开发日记

这里主要记录这段时间开发小程序过程当中遇到的坑和要注意的点。主要是但愿在之后开发小程序的过程当中能在评审需求的时候就发现哪些能实现,哪些实现起来比较困难。这样就能在定设计和交互以前尽量的减小后期踩坑的风险。javascript

下拉刷新

自定义的下拉刷新

微信自带的下拉刷新须要在配置中开启:html

  1. 配置 app.json 中的 window或者单个页面的json文件
属性 类型 默认值 描述
backgroundTextStyle string dark 下拉 loading 的样式,仅支持 dark / light
enablePullDownRefresh boolean false true 开启 false关闭
  1. 页面中经过onPullDownRefresh方法监听下拉动做
onPullDownRefresh() {
    setTimeout(() => {
      wx.stopPullDownRefresh()
    }, 1000)
  }
复制代码

这里有个要注意的问题:
onPullDownRefresh中不能调用wx.startPullDownRefresh(),不然会死循环java

自定义的下拉刷新,目前只支持整个页面的下拉刷新,对于局部的下拉刷新,就没有办法了:android

局部的下拉刷新ios

foo

这种咱们可使用自定义下拉刷新的方式来实现。详细的能够看个人另外一篇博客,这里也就不赘述了。web

关于自定义顶部navigationBar

小程序自带的navigationBar仅能够在json文件中配置。提供的可配置项也是少的可怜。主要以下:chrome

属性 类型 默认值 描述
navigationBarBackgroundColor HexColor #000000 导航栏标题文字内容
navigationBarTextStyle string white 导航栏标题颜色,仅支持 black / white
navigationBarTitleText string 导航栏标题文字内容

从上面的表格能够看出来,顶部导航栏样式固定,咱们仅能够修改文字,字体颜色和背景色。json

不过还好小程序还提供了自定义顶部导航的配置,window.navigationStyle,这个配置项支持两个值default|custom。默认是default,表示的是用小程序自带的导航栏,配置为custom时是自定义导航栏,其实就是小程序隐藏掉导航栏,而后咱们本身实现。canvas

可是自定义导航栏不只带来了设计上的自由,也带来了不少坑。小程序

下拉刷新

不一样于web开发,小程序和app对于下拉刷新的需求很是的多,也算是基本功能之一,小程序自己也自带下拉刷新。咱们只需将window.enablePullDownRefresh设置为true,而后在页面监听onPullDownRefresh便可。

可是当咱们用到自定义navigationBar的时候,会发现,原本fixed定位在顶端的navigationBar会被一块儿拉下来。

系统自带的navigationBar的下拉刷新

foo

自定义navigationBar的下拉刷新

foo

这个时候咱们就必需要使用自定义的下拉刷新。关于自定义的下拉刷新的实现原理这里就很少说了。可是实现起来在真机中发现,android手机会有明显的卡顿。

层级问题

按照正常的navigationBar,通常这个组件的层级是最高,仅次于遮罩层和弹窗这些组件。通常的组件可使用z-index属性来控制层级。

可是小程序中有种概念叫作:原生组件

这些组件包括cameracanvasinput(仅在focus时表现为原生组件),maptextareavideolive-playerlive-pusher

这种组件脱离于WebView渲染流程以外,层级也是最高的,所以不管z-index设置多大,都没法覆盖原生组件。

系统自带的navigationBar

foo

自定义navigationBar

foo

虽然理论上咱们能够用cover-viewcover-image来实现自定义的navigationBar,可是我的以为仍是尽可能避免使用自定义的navigationBar

虽然cover-viewcover-image组件能够覆盖在部分原生组件上面。对于原生组件之间,可使用z-index来控制他们的层级。

可是小程序cover-view组件内部只支持嵌套cover-viewcover-image以及button。这在很大程度上不支持咱们做出多么有个性化的组件。并且实现起来坑也不少。

并且关于用z-index来控制层级这点也存疑,虽然文档上这样说明,可是,我在开发中发现,实际上仍是看渲染的顺序。后渲染的始终在先渲染的上层。

键盘弹起时会将顶部导航栏顶上去

这个是针对textarea组件在页面底部的时候,准确来讲是textarea组件距离底部的距离没有键盘高的时候。在键盘弹起时形成了整个页面上移,从而致使了导航栏会移到页面外。

当键盘未弹起时

foo

当键盘弹起时

foo

固然这个不算是硬伤,毕竟出现的条件有限,咱们能够在设计上尽可能避免将textarea放到底部来避免这个坑。

自定义底部tabbar

自定义的tabbar

在说自定义以前先看看小程序自带的tabbar能够作到什么程度。

自定义的tabbar是在app.json中配置的,在tabBar下:

  • 基本配置
属性 类型 描述
color HexColor tab 上的文字默认颜色,仅支持十六进制颜色
selectedColor HexColor tab 上的文字选中时的颜色,仅支持十六进制颜色
backgroundColor HexColor tab 的背景色,仅支持十六进制颜色
borderStyle string tabbar上边框的颜色, 仅支持 black / white
list Array tab 的列表,详见 list 属性说明,最少2个、最多5个 tab
position string tabBar的位置,仅支持 bottom / top
custom boolean 自定义 tabBar,见详情
  • list选项配置
属性 类型 描述
pagePath string 页面路径,必须在 pages 中先定义
text string tab 上按钮文字
iconPath string 图片路径,icon 大小限制为40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon。
selectedIconPath string 选中时的图片路径,icon 大小限制为40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon。

因此从上面咱们能够看到,咱们能够定义tabbar的选中和未选中图标和字体颜色。没办法加入别的样式和嵌入别的自定义点击事件。

自定义的几种实现方式

  1. 组件形式

这是比较老的版本的形式。在须要tabbar的页面嵌入tabbar组件。这是最简单的实现方式。可是在首次切换的时候,会有很明显的闪屏。

  1. 官网提供的customer-tab-bar的形式

这个比第一种要好点,也是我在项目中用到的一种模式,可是切换的时候也有稍微的闪屏

  1. tabbar的形势

这种实现方式稍微复杂,也就是将首页的几个页面做为组件传入,经过路由控制页面切换。

之因此叫伪tabbar的形势,是由于这个只是表面上是tabbar

理论上这种方式实现的在切换的时候能够作到不闪屏。可是会不会带来别的问题呢?

好比说返回的时候会不会形成页面错乱?
本来的页面生命周期和组件的生命周期略有不一样,会不会形成一些坑?
还有个几乎能够确定的问题,就是若是不使用cover-view的话,咱们就无法盖住原生组件。

不过好在小程序组件和页面之间的切换很方便,特别是在用Taro以后,组件和页面的区分仅仅只是是否在app.tsx中注册。因此第二和第三种实现方式切换起来并非很麻烦。可是目前看来的话第二种实现方式体验还算满意,所以也没有必要切换到第三种方式。

关于弹窗

额,其实我说的这三个,几乎能够总结出一个问题,那就是小程序中让人吐血的层级问题。

其实不管是弹窗仍是navigation仍是tabbar他们都有一个特色,就是定位在页面的某一个位置,还有层级要足够高,要可以覆盖住底层元素。

官方没有专门的弹窗容器(我以为应该有一个弹窗容器)所以只能靠咱们本身写了。可是由于cover-view使人蛋疼的样式支持度,我的以为仅仅用cover-viewcover-image来实现一个定制化的弹窗几乎不可能。

若是不用cover-view你会发现不少经常使用的组件都是骑在你脸上,而你毫无办法的。

所以我的建议,在有原生组件的页面上,尽可能避免弹层的出现。

若是是在没法妥协,那也建议弹窗组件分两块来写,一种专门用cover-viewcover-image来写,而且必定要写z-index来控制层级,理论上是后面的元素会覆盖在上一个元素上面,可是仍是要防止有些组件在操做的过程当中从新渲染,而改变原有的层级。而对于页面中没有原生组件的,能够用view来写,这样样式上就自由不少。

关于html2wxml

关于富文本的渲染。如今基本的作法都是先把html解析为节点信息,而后再经过模板渲染为wxml。可是由于小程序模板不支持递归调用。因此在不少第三方组件中都出现如下的代码:

<!--temp0-->
<template>
...
  <template is="temp1"></template>
</template>
<!--temp1-->
<template>
...
  <template is="temp2"></template>
</template>
<!--temp2-->
<template>
...
  <template is="temp3"></template>
</template>
...
复制代码

一般这种代码会出现十几到二十几个,也就是说最多支持嵌套二十多层。若是不够的话就得本身加了。我就遇到过一个富文本,足足嵌套到了两百多层。我复制到一百的时候实在受不了了,写了一个模板生成器来完成。

网上有人说这种代码看起来蠢哭了。的确,可是也很无奈。

时间格式化问题

这个不能说是小程序的坑,应该说是ios和android对new Date()处理上的差别。咱们能够用safari浏览器和chrome来复现这两种差别

咱们公司先后端交互用的时间格式是YYYY-MM-DDTHH:mm:ss。这种格式的时间字符串用new Date()来处理,在safarichrome的表现以下:

new Date('2019-05-29T14:00:00')
// safari Wed May 29 2019 22:00:00 GMT+0800 (CST) = $2
// chrome Wed May 29 2019 14:00:00 GMT+0800 (中国标准时间)
复制代码

safari是比chrome要早8小时的,这是由于chrome认为这个时间是本地时间,而safari认为是国际标准时间,因此会有这样的8小时差别(仅限于中国)。

所以在调用new Date()以前咱们须要把YYYY-MM-DDTHH:mm:ss格式的转换为YYYY/MM/DD HH:mm:ss这种格式的字符串。

此外,我在处理的过程当中还发现带毫秒数的事件字符串2019-05-29T14:00:00.000,这种的还须要将毫秒数去掉变成这种格式2019/05/29 14:00:00。而后在iosandroid上表现也就一致了。

function getDate(date: any) {
  if(typeof date === 'string') {
    return new Date(date.replace('T', ' ').replace(/\-/g, '/').split('.')[0])
  }
  return new Date(date)
}
复制代码

字体

小程序在android下,字体的font-weight必需要设置到700及以上才会变粗,或者统一使用bold

ios

foo

android

foo

小程序分包

小程序大小是有限制的,目前是主包不超过2M。但是为了实现一些功能,致使咱们很容易就超过了这个限制。

好在官方提供了分包方式。具体能够参照官方文档

就一点:对于副包内引用的,较大的包,应该包含在分包的文件夹内部。否则仍然会打包在主包内部

关于pxrpx

不能无脑的全站用rpx来作适配

最近在作一个需求,以为有个点仍是须要注意的,特此记录一下。

这个需求就是一个简单的消息轮播。以下图:

foo

就是红框区域的一个向下无限滚动轮播,时间间隔为2s。我是使用translateY来实现的。每次translateY的高度和消息块的高度相同。

可是在滚动的过程当中,发如今某些机型上面每次滚动都会有细微的偏移,而在某些机型上面正常。

消息显示窗口的高度和每一个消息的高度都是80rpx。代码以下:

<View className="notice-pannel" style={{transform: `translateY(${curIndex * -80}rpx)`, transition}}>
{
  list.map(item => (
    <View className="notice-item" key={item.id}>
      <Image className="notice-avatar" src={item.actor.avatar_url}></Image>
      <Text className="notice-desc">{`${item.actor.login} ${item.payload.action} ${item.repo.name} at ${new DateX(item.created_at).format()}`}</Text>
    </View>
  ))
}
</View>
复制代码

最后定位问题的缘由是由于部分屏幕宽度在换算rpx的时候会有偏差,致使每次translateY的时候会有一个小偏差。

rpx根据官方文档的定义是:rpx(responsive pixel): 能够根据屏幕宽度进行自适应。规定屏幕宽为750rpx。

所以,会有些屏幕宽度在rpx转px的时候会有除不尽的时候,这时候每每会有四舍五入取整的状况。

在看这行代码${curIndex * -80}rpx),假设咱们的设备的屏幕宽度为412这时候80rpx专成px的时候是43.946666666666665px。开发者工具上会发现,其实是换算成了43,也就是每一个消息块的高度是43px

curIndex2的时候,实际上咱们应该偏移43 * 2也就是86px,但是若是是直接用rpx的话,咱们发现会是87px。这时候就产生了偏移了。

知道缘由的话解决方案也有了,就是用px作单位就能够了

<View className="notice-pannel" style={{transform: `translateY(${curIndex * rpx2px(-80)}rpx)`, transition}}>
{
  list.map(item => (
    <View className="notice-item" key={item.id}>
      <Image className="notice-avatar" src={item.actor.avatar_url}></Image>
      <Text className="notice-desc">{`${item.actor.login} ${item.payload.action} ${item.repo.name} at ${new DateX(item.created_at).format()}`}</Text>
    </View>
  ))
}
</View>
复制代码
相关文章
相关标签/搜索