本站WordPress +“微信小程序”实战系列文章已经到了第五篇,这次记录的是“DeveWork极客”小程序v2.0 的更新。2.0 版本在UI 上改动不大,但是“内核”却做了大改动——这些改动旨在提升小程序运行速度及降低性能消耗。
如果你没有看过本小程序,可以通过下面的小程序码进入体验。注意看文章的此时你扫码进入的版本可能不是2.0 版本了。
还是一样,如果你是第一次看本系列文章,建议先过目之前的文章:
《WordPress 网站基于REST API 开发“微信小程序”实战》
本系列文章虽然是WordPress 作为角色之一来写,但小程序的部分其实是共通的,如果你是开发小程序的,不妨也一看。坑都是在那,而我却帮你提前踩了不少。
将WordPress 作为小程序的后端,建议是做一些针对性的优化(如《WordPress REST API 定制化输出》)以减少HTTP 请求传输过程中不必要字节数。Jeff 本身对自己的WordPress 做了很好的优化,但作为小程序的坚实后端,对此产生的效果还是不满足啊。
以WordPress 作为后端驱动的小程序,一般而言是资讯(内容)展示型的小程序,往往涉及到一些额外的数据处理,如借助wxParse 做富文本转化,日期等数据段的转义。这些放在服务端(WordPress)或者客户端(小程序)中做都可以,但一般而言我们希望是在服务端就能完成。
另外,作为内容展示型小程序,对于数据的实时性要求不高,所以很有必要做相关的缓存策略。WordPress 本身有不少成熟的缓存方案,但对于小程序而言我们可以做到更多。
基于以上总总,开发“DeveWork极客”小程序2.0 版本时,Jeff 对整个小程序后端做了如下的架构变化:
1)原来的WordPress 端除了现有的优化,基本不做其它处理。
2)用Node + Redis 写了一个小型的后端,用来转发与缓存 WordPress REST API,Redis 作为内存数据库的缓存机制确保了读过程的快速;这个额外写的后端承载的另外功能是,将原本在小程序端进行的数据处理(如wxParse 的html2json、评论数据重新排序等)搬到这个后端进行。小程序端基本上只是纯数据的渲染,大大降低了小程序端的运行性能要求及提高运行速度。
用下面的图直观表示就是:
实施了以上的效果如何呢?让我们来看下。
1)在尽量保证其它同等条件下,对某篇文章的请求结果对比:
2)原REST API 数据对比:
实际使用起来的对比效果么,就见仁见智了。在我看来,因为本来就优化得很好,所以并没有“立竿见影”的那种效果,倒是锦上添花了。
除了后端的变化,在客户端(小程序端)还做了如下的优化工作:
1)预加载与本地localStore 缓存。当用户进入“DeveWork极客”小程序首页,有很大的概率是会去点击第一篇文章,因此在加载完文章列表并展示后会去请求第一篇文章的文章详情数据并缓存到LocalStore 中。因为异步的关系用户是无感知的,而当用户真正点击了第一篇文章会直接加载LocalStore 的内容——这时候用户感觉到的就是快。
2)根据像素密度(pixelRatio)进行图片的云端处理。在这里就不解释“像素密度”的含义了,通俗地举个例子:原来600x600 大小的图片在iPhone7p(pixelRatio =3)上是最佳清晰度(兼顾清晰度与文件大小的“最佳”)的,那么在iphone7(pixelRatio =2)则是400x400 大小就好,再小则不清晰,再大则浪费。屏占比可以通过wx.getSystemInfo()
小程序接口获得。
关于小程序的性能优化上,后面Jeff 会专门写一篇文章,敬请关注。
为了配合新增的评论 + 收藏功能,2.0 版本在文章详情页增加了一个浮动的FixBar,上面有“返回+写评论+评论数+收藏+分享”的几个icon 及其入口。开诚布公,这个FixBar 借鉴于IT之家的移动端相关页面,对,设计上非原创。
返回功能,配合实战(四)提到的文章内链功能做了如下区分:当是通过文章内链进来的文章,icon 是HOME 且点击返回首页。其它情况则是返回上一层页面。
写评论跟评论数的入口,后文会有介绍。值得吐槽的是,点击评论数的icon 会跳转到评论区域,感觉小程序的wx.createSelectorQuery()
接口还是有许多bug。
收藏与分享入口,实现起来也简单,就不多说了。
2.0 版本另外一个重要的功能是加入了评论相关功能。评论列表的展示用到的WordPress REAT API 接口是https://example.com/wp-json/wp/v2/comments?post={id}&per_page={per_page}&page={page}
。
文章评论一般放在文章详情页面,为了兼顾用户体验,Jeff 是处理成按需加载的方式——默认在文章页面进入的时候不加载评论数据,而是用户拉到页面底部的时候才产生请求。毕竟有些用户可能连文章第一段都没看完就离开的,按需加载才是王道。
另外,上面的Comment API 默认的数据段是按照时间排序的评论数组,在 WordPress 中存在的父子评论关系在 API 中是通过parent
与id
两个字段联系起来。为了在小程序前端的评论列表中也体现这种父子评论关系,必须要进行相关数据结构处理。Jeff 在这里是仅展现一级的父子评论关系,数据结构处理是直接放到上一章节的提到的“Node 后端”上进行,返回到小程序端的已经是二次处理好的数据(包括评论时间改成"xx前"这种格式),小程序端直接渲染数据即可。
另外,还与本站评论表情打通,使得在小程序端也能正常显示这些自定义表情图片。具体的实现方式其实也很简单,比如哭的表情,将:cry:
转化为小程序的Image view 然后添加相应CSS 就好(效果见上图)。
WordPress 的发布评论的接口是https://example.com/wp-json/wp/v2/comments?author_name={昵称}&author_email={邮箱}&content={评论内容}&post={文章id}
,POST 方法。不过你默认发过去会显示如下:
为了安全,WordPress 默认是不允许开启匿名评论。但可以通过如下代码去hack 下:
| // https://cloud.tencent.com/developer/article/1025777 // REAT API 允许匿名评论 function dw_rest_allow_anonymous_comments() { return true; } add_filter('rest_allow_anonymous_comments','dw_rest_allow_anonymous_comments'); |
|:----|
开启匿名评论后,请自行采取一些措施确保该接口不会被滥用,Jeff 的话是采用类似JWT(JSON Web Tokens)的验证形式确保安全的。
小程序的用户常规能获取到的昵称+头像URL,可以作为评论的基本信息。WordPress 中的评论则是昵称+邮箱+网址(可选)作为基本信息。为了将这两种账户体系打通,Jeff 是把小程序的用户头像URL 作为WordPress 评论的“网址”字段,然后在PC 的主题上也做了相应的改造。
小程序端的评论输入框,本来是想用textarea
组件来做,发现有个百思不得其解的坑:采用浮动定位,form
下的是textarea+submit btn 组合,这个时候在手机上点击按钮死活退出不了焦点,即使强制去控制focus
属性为false
。后面实在不想再花时间去排查,明智地用input
组件算了。
另外值得一提,发现在小程序发布评论,评论内容包含emoji 的不能正常发布。后面排查了,应该是emoji 编码问题导致的,现阶段处理方式是过滤掉emoji。
收藏功能跟阅读浏览功能类似,具体代码就不展示了,也是利用LocalStore。目前仅支持保存在本机设备,后面会接入云端同步功能。
相关文章的功能,Jeff 为了减少额外的请求,是集成到文章详情的API 上去的。5篇相关文章的实现,默认是展示该文章同标签下的文章,如果不足5篇,则通过同分类的文章补足。在这里献上PHP 的核心代码:
| // https://cloud.tencent.com/developer/article/1025777 // 在rest api 上输出相关文章 function raa_get_related_posts_by_id( $postid ) { $post_num = 5; $exclude_id = $postid; $posttags = get_the_tags(); $i = 0; $result = array(); if ( $posttags ) { $tags = ''; foreach ( $posttags as $tag ) { $tags .= $tag->term_id . ','; } $args = array( 'post_status' => 'publish', 'tag__in' => explode( ',', $tags ), 'post__not_in' => explode( ',', $exclude_id ), 'ignore_sticky_posts' => 1, 'orderby' => 'comment_date', 'posts_per_page' => $post_num ); $tags_query = get_posts( $args ); foreach ( $tags_query as $tag_post ) { $temp = new stdClass(); $temp->id = $tag_post->ID; $temp->title = $tag_post->post_title; $featured = get_post_meta( $tag_post->ID, 'featured', true ); if ( $featured ) { $temp->featured_image = $featured; } else { $temp->featured_image = get_post_meta( $tag_post->ID, 'thumb', true ); } $result[] = $temp; $exclude_id .= ',' . $postid; $i ++; } wp_reset_query(); } if ( $i < $post_num ) { $cats = ''; foreach ( get_the_category() as $cat ) { $cats .= $cat->cat_ID . ','; } $args = array( 'category__in' => explode( ',', $cats ), 'post__not_in' => explode( ',', $exclude_id ), 'ignore_sticky_posts' => 1, 'orderby' => 'comment_date', 'posts_per_page' => $post_num - $i ); $cats_query = get_posts( $args ); foreach ( $cats_query as $cat_post ) { $temp = new stdClass(); $temp->id = $cat_post->ID; $temp->title = $cat_post->post_title; $featured = get_post_meta( $cat_post->ID, 'featured', true ); if ( $featured ) { $temp->featured_image = $featured; } else { $temp->featured_image = get_post_meta( $cat_post->ID, 'thumb', true ); } $result[] = $temp; $exclude_id .= ',' . $postid; $i ++; } wp_reset_query(); } return $result; } |
|:----|
代码有点挫,毕竟好久没有写PHP 了。如果你有更好的实现方式,欢迎分享。
其它的优化功能仅罗列下:
1)文章页面、“我”的tab 页面在UI 上做了一些修改;
2)修复了在安卓上一些样式问题;
3)增加了一些广告入口;
4)优化了全局Loading 的展示方式;
5)图片增加个placeholder,并配合新的1.5基础库在某些地方启用 lazyload。
本文完。