最近开发了一款小程序,主要是展示近期的一些最新、最火的电影以及相关信息,该小程序由首页、列表、详情、评论、视频这几个页面构成。虽说开发过程还算顺畅,但在其中,也遇到一些难搞的问题,为方便日后参考,因此把部分问题列举于此:

一、请求不在以下 request 合法域名列表中

如果你的小程序使用了服务端接口,当你在本地开发时,可能会遇到如下错误:

接口报错

出现这种情况,是因为没在后台设置request合法域名。如果你只是本地开发,用于某些测试,你可以在 微信web开发者工具 中的 设置 -> 项目设置 里作如下设置:

工具接口设置

但倘若你要发布到线上,那你得登录微信公众平台的后台,设置相关服务器域名。如果你的小程序需要调用多个接口,你也可进行设置多个。

后台设置域名

二、网络接口必须是https

对于小程序接口,要是在从前,你可以使用 http 协议,也可以用 https 协议。但现在,你的网络请求接口协议必须是https。

详见 关于公众平台接口不再支持HTTP方式调用的公告

但要注意,服务器域名修改后,一定要在 微信web开发者工具-清缓存、重新编译。

或许有的时候这样做并不管用,那么,你得重启 微信web开发者工具。

三、配置文件不生效

我们知道,每个小程序的根目录都有一个 app.json 文件,它用于对该程序的全局配置(标题栏文字、界面风格、底部tab)。但为了保证某个页面能够单独设置相关属性,小程序规定,可以给每个页面目录都配置了一个 *.json 文件。

但要注意的是,每个目录下的 *.json 文件,一定要与当前目录文件同名。比如,pages/comment 目录里,必须是 comment.json。否者,json文件配置不会生效。

四、video元素无法播放

因为是电影相关的小程序,所以少不了视频界面。其中,使用了小程序提供的 video 元素用于播放电影预告片。

当在微信开发者工具预览效果时,却在控制台出现了如下错误:

视频出错

因为是引用的是第三方视频资源,最初我以为是该远程视频服务器加了防盗链。于是,我上传了一段视频到我的服务器,再在小程序里引用它,嗯,视频可以正常播放了。接着,再扫码真机测试,但却出现如下界面:

视频截图2

视频区域一片漆黑,没有播放按钮,没有加载,什么情况?

搜索了各方资料,有说是基础库问题,有说是手机系统问题,还有说是视频格式问题,时间一分一秒过去,最后还是无果。

通过上面的截图,我一开始是把视频内容放在页面底部(页面超过一屏,即视频内容在第一屏之外),后来我又在页面顶部放一个相同的视频区,再真机扫码测试。

结果,页面顶部的视频可以播放,但底部却还是一片漆黑。难道跟布局有关?于是,在公共样式里看到这么一行代码:

/* app.wxss */

page {
height: 100%;
overflow: hidden;
}

尝试把它删除,在扫码测试,结果底部视频也能正常播放了。因此,如果设置了以上样式,解决方法就要把视频区放在第一屏中,或者,直接删除该样式。解决后截图如下:

视频截图3

五、iOS页面滑动卡顿

本以为小程序在 iOS 和 android 系统上表现一致,但当用iOS扫码测试时,发现在滑动页面时很不流畅,即手机滑动一段距离,页面只是移动一段距离,有时甚至不会移动。

一开始以为是列表页没有使用 scroll-view 组件原因所致,但很快发现详情页也出现滑动卡顿,要知道详情页并不适用 scroll-view 组件。所以,应该不是组件的问题。

由于iOS测试的是我线上的版本,当我再用iOS测试本地开发版本(该版本新增并修改了一些内容)时,列表页和详情页,都能顺畅滚动。

对比这两版代码,在样式上发现线上(旧)版本多了这些样式:

/* app.wxss */

page {
height: 100%;
overflow: hidden;
}

.container {
height: 100%;
overflow-y: auto;
}

尝试在本地开发版本加入上面的样式,再iOS扫码测试,结果滑动页面都变的卡顿起来了。解决方案,还是把类似样式删除。

六、wx.pageScrollTo 不生效

微信小程序提供了 wx.pageScrollTo(OBJECT) 方法,它可以将页面滚动到指定位置。

当进入到一个列表页,并且你希望页面滚动到某个位置时,你可以用到该方法。但当列表页面涉及到ajax请求数据列表时,即便你把该方法放在请求回调中,页面也不会滚动到指定位置。如:

wx.request({
url,
data,
success: res => {
wx.pageScrollTo({scrollTop: 1000});
}
});

猜测可能与页面渲染速度有关,于是设置一个延时执行页面滚动方法,问题便得到解决。

setTimeout(() => {wx.pageScrollTo({scrollTop: 1000 });}, 200);

七、循环警告

当在小程序里循环渲染一组数据时,可能在控制台出现如下警告:

循环警告

之所以这样是因为可能会出现动态列表、但这些列表项又得保存对应的特征和状态,并且为了提高渲染性能。因此,你需要使用 wx:key 来指定列表中每项的唯一标识符。

当渲染的数组项只包含本身时,你可以在 wx:key 上使用保留关键词 *this,即:

<view class="item" wx:for="{{list}}" wx:key="{{*this}}"></view>

当渲染的数组项为复合属性时,你可以在 wx:key 上使用每项对应的某个属性(假设每项包含 name 属性),比如:

<view class="item" wx:for="{{list}}" wx:key="{{item.name}}"></view>

八、多重循环

如果数据涉及多重嵌套,如:

...
data: {
list: [
{
name: 'movie1',
type: [{desc: 'a'}, {desc: 'b'}]
},
{
name: 'movie2',
type: [{desc: 'a'}, {desc: 'c'}]
}
]
}

那么在 wxml 中,可以这样来循环出 type:

<view class="item" wx:for="{{list}}" wx:key="{{item.name}}">
<view class="name">{{item.name}}</view>
<text wx:for="{{item.type}}" wx:key="item.name">{{index}} : {{item.desc}}</text>
</view>

九、<text></text> 之间的空白与视图关系

借上面的数据和试图,当 text 组件里的 <text></text> 之间有空格,或者没空格时,会呈现出不同的试图,见对比(这里只展示text代码),为了保证页面在手机屏幕下,示例代码块不折行,这里代码也使用的图片:

下图分别展示 text 组件一行、两行、三行的情况:

text组件空白与视图

可以看到,当 text 组件不换行时,视图中循环后的两个 text 处在同一行。而当 text 组件换成两行时,视图中循环后的两个 text 各占同一行。当 text 组件换成三行时,视图中循环后的两个 text 前面有一个空白行。

十、图片路径

要在界面展示图片一般有两种形式,即 标签引入 或者 标签背景。

针对 标签引入,小程序定义了 image 组件,该组件可以引入本地图片,也能引入远程服务器图片。

<image src="pic.png"></image>

<image src="http://www.xx.com/pic.png"></image>

上面两种路径写法,都能正常的显示图片。

但对于 标签背景 形式,倘若使用本地图片,如:

<view class="box"></view>

.box {
width: 100px;
height: 200px;
background-image: url(pic.png);
}

则组件的背景图不会显示,在控制台将看到以下错误:

本地图片加载失败

即WXSS文件无法读取本地图片,我们得把它替换成远程服务图片(绝对路径),这样,背景图片才能正常显示。

但如果你非要使用本地图片,也不是不可以。只是你得先将本地图片转换为 base64,再引入到背景样式中,这样,也能正常显示。

十一、事件对象里 currentTarget 和 target

和JavaScript事件一样,小程序里事件函数带有一个 event 参数,它包含一组信息。

值得注意的是,event对象里的 currentTarget 和 target 属性。其中,target 为 触发事件的源组件,而 currentTarget 为事件绑定的当前组件,这两者需要区别。

在处理组件前,我们会在组件上加 data-* 属性,而在事件中,再通过 event 参数里 currentTarget(或者target) 的 dataset 属性读取相应的值。

十二、canvas 等原生组件层级最高

通过官网资料,map、video、canvas、textarea等原生组件层级最高,无论其他组件设置多大的 z-index,也不能覆盖在原生组件之上。

但迫于一些特殊需求,我们需要在这些原生组件上覆盖一些其他组件(比如map上的操作按钮、canvas上的提示弹层),那么有没有方法实现呢?

答案是肯定的。经过尝试,发现目前主要有四种方法,总结如下:

  1. 虽然普通组件不能覆盖原生组件,但是原生组件之间却有层级关系,根据渲染效果,后插入的原生组件层级更高。因此,可以考虑用后插入的原生组件覆盖之前的。
  2. 利用原生组件的控件,比如 map 的 controls。
  3. 在普通组件覆盖原生组件时,可以先暂时把原生组件隐藏。该方法在 Android 上没问题,但 iOS 却发现 canvas 组件不会被隐藏,仍然覆盖在最上层。
  4. 使用 cover-view 组件,它是因为原生组件的层级问题而专门定义的组件。所以,基础库 1.4.0 才开始支持,低版本需注意作兼容处理。