Weex项目实战及踩坑记录

游星啊 2018-07-31 10:24:26 1841
本文来自 唐笛_Dylan ,作者 游星啊

一.背景

目的地互动作为航旅业务中主打用户心智的重要阵地,在11月份迎来了它的第三期改版。而作为一款主打心智的产品,注定它对用户体验要求很高。同时它又有外投到手淘,UC旅行头条等多渠道的需求。所以在技术选型上,时下正火热的集团跨平台开发框架-Weex成为了我们最合适的选择。但是目前我们正跑在线上的Weex页面多是纯展示页面,不涉及到复杂的逻辑以及跳转,而目的地三期项目相对来讲页面繁多,结构复杂,所以目的地三期项目除了本身的业务意义以外,也有它的技术意义----对于Weex来讲,它到底能做到一个怎样的程度?

二.项目准备

概述:项目前期准备的主要精力按功能主要分为两方面,一是Weex技术本身,首先我是第一次接触Weex开发,所以要完成这么一个项目,对Weex框架的掌握程度对于项目的完成度来讲至关重要,另外对于目的地三期本身的功能点来讲,我们对Weex桥接能力的前期调研也必不可少。二是开发项目不可或缺的与服务端定接口能力,定数据结构,稍微不同的是,对于返回结构来讲,我们还需要考虑到这套数据结构是Weex便于处理的。

1.Weex桥能力的调研

以"Weex的LBS接口两端(旅客,手淘)支持调研"为例

需求:我们需要拿到用户所在位置的经纬度,然后反解出该经纬度所在的城市名,交由服务端判断是否为用户所在的常驻目的地。由于航旅业务的特殊性,我们还需要关注桥是否支持境外经纬度的反解功能。

调研:经过调研,发现手淘和飞猪都有获取当前位置的桥方法,但是两端的调用方法并不一样。后来这块儿是借助了wx-bridge(JS层抹平差异,脏代码的集中营)来实现业务层调用方式的统一,使用起来方便了很多。但是后来经过调研,手淘LBS桥底层是采用的高德地图SDK,并不支持国际位置的反解。所以最后采用的方案是使用服务端接口来完成整套的反解+是否常驻地逻辑。

小结:从桥方法的调研可知,Weex的跨平台是建立在标准之上的每个接入Weex的客户端就像是一个Weex浏览器一样,他们可以提供统一的渲染,显示。但是Weex页面也需要底层提供出自己的开放能力,这是容易受制约的。而且开放出来的能力能不能被信任也得打一个问号,,因为一个能力涉及到的细节很多,方案的不同会使平台之间提供的能力也并不是全等的,这会在一些特殊需求上,在一些细小的点上被卡住,比如手淘使用的高德地图SDK不支持国际位置的反解,而且遇上这些问题之后,作为Weex的使用者通常来讲都是比较无奈的。因为推动不同端之间的底层能力统一成本巨大,周期较长。所以我觉得从某种程度上来讲,标准的统一在当下的Weex环境中应该是被第一优先级考虑的事情。

2.Weex学习

对于我来说,是第一次使用Weex技术进行开发。于我个人而言,类Vue框架的编写模式,新的MVVM设计思想(双向绑定,也会有很多坑。这种模式适合怎样的页面(纯展示,表格)),JS语言基础,以及CSS式的布局方式,对我来讲都是一扇扇新世界的大门。

学习历程:

1.Weex基础:这部分包括了类Vue框架的编写模式,JS语言基础,以及CSS的布局方式。

学习一门新技术个人习惯是先看官方文档。然后对着官方文档上的例子一步一步先跑起来。花上一两天的时间基本就可以对整个Weex的大概机制,语法,常用标签,属性有一个大致的了解。

但是现在的官方文档还是不够细致(目前Weex团队正在全力准备一份更加详细友好的文档),所以之后的主要学习积累在学习Weex playground的源码。码中自有黄金屋,很多文档上不曾提到的知识点或者是标签属性都在代码中有实例。而且通过代码的实操,对于客户端开发来讲(特别是针对习惯于计算绝对布局的iOS开发),对于flex box盒子模型的布局会有更深的理解。我有一个心得就是:在玩手机的时候,看到某一块界面可以脑补一下如果用flex box的布局方式要怎样去实现。或者是对着playground或者weex-ui的界面想一下自己的实现方式,再对比一下源码的实现,再去不断的改进自己的设计。

2.MVVM设计思想

对于客户端开发来讲,面临的另一个挑战就是从MVC的设计思想到前端界已很通用的MVVM设计思想的转变。谈谈我自己的理解,比较MV-C和MV-VM来讲,它们之间的区别就是如何描述M与V之间的关系。对于MVC,Model和View之间的关系是由Controller来负责的。它控制了整套Model变更之后,View应该如何刷新的逻辑。而对于MVVM来讲,Model和View之间是由一种中介,桥梁--View Model来进行连接。View Model的核心在于双向绑定,它替代了Controller层的控制,以及这部分的业务逻辑。当View Model进行了变化之后,会经过diff操作之后,对变更部分直接触发了界面的重新渲染。

打个比方,相较于汽车来说,MVC就像是手动挡,它的升档和降档逻辑由人脑去控制(数据Model变更之后的界面操作需要自己在Controller层实现)。而MVVM就像是自动挡,当变速箱检测到发动机转速的变化之后,它会自动去按照已经编写好的变速策略执行升档降档操作(数据Model变更之后的界面刷新操作,由View Model自动去通知界面进行更新)。

3.组件式分工开发模式

相比于Native开发模式,我们通常会按照页面,或者是功能点分别进行开发。页面与页面之间,功能与功能之间相互独立,互不影响。但是经过我们的实践,我们认为Weex开发更适用于组件式分工开发模式。即在拿到一个设计稿之后,对每个页面进行解构,分解成一个一个组件,然后分工去领取组件开发。每个组件就像是一个独立的模块,它内部已经包含了所有的逻辑,也便于开发人员快速自测验证。组件开发完毕之后,就可以让每个人负责一个页面去像堆积木一样,快速把整个页面搭出来。

三.开发过程问题记录

整个开发过程被分为以下几个阶段:

1.组件开发阶段

概述:这个阶段基本上还是属于比较轻松愉快的。更多的是一个学习,适应的过程。积累了一些UI开发的经验,也踩了一些多端适配以及数据绑定上的坑。这些坑有文档阐述不清,无文档可查的原因,有的是系统原生差异带来的不一致,有的是Module实现上并未在细节上进行验证,也有的是Weex尚在起步阶段,官方还没来得及提供一些贴合开发需求的好用的feature。详细如下:

1.某一个组件完成数据绑定是在第一次传入数据时完成的,后面发生数据变更,如果有新增属性,并不会触发数据更新。(关键词:数据绑定)

2.当flex-direction为column的时候,它的子节点的宽度是默认占满全屏。但是text组件目前还不支持自适应宽度,所以在需要Label在竖排条件下进行宽度自适应的时候(如有border的情况下),可以在外层包上一层Div。(关键词:UI实践经验)

3.Class支持条件选择,可以让整个界面更加灵活多变,代码结构更加清晰。

eg:

4.即使展示的text为空,text组件还是会预留出一个小宽度。如果存在border的情况下,显示会很奇怪,需要进行特殊处理。(关键词:UI实践经验)

5.iOS和Android中的text组件默认的文字的上下padding不一样(Android会多留一些padding空间)。所以如果Column排列的组件中含有text组件,最好不要写死组件高度,让整个组件高度自适应。(关键词:UI实践经验)

6.Android和iOS通过桥接方法获取的数据类型不一样,如user module的getUserInfo方法,storage Module的getItem方法。Android是originType,而iOS则返回的是字符串,所以需要做兼容处理。(关键词:多端适配)

7.0.5px的border-width在部分Android手机和iPhone6等机型上会出现完全不显示,或者是显示部分等显示问题。所以尽量不要使用0.5px宽度的border。(关键词:UI实践经验)

eg:

8.目前text并不支持属性字符串的显示(Weex官方正在支持中),所以在实现一些特殊需求,如昵称和评论内容颜色不一样,要使用一些比较hack的方式在实现(text拼接)。

eg:

9.Border-width在HTML里实现,它表现为一个div的外延伸,即div本身宽度为100,如果border-width是20,div的总宽度就是div本身的宽度加入border的宽度。而Weex里面不一样,border表现为div的内延伸,即div的总宽度不变,border会挤压内部空间。这点在进行布局计算的时候,需要注意。(关键词:UI实践经验)

HTML效果图:

2.页面拼装,联调阶段

概述:到了页面联调阶段,问题就更加集中在数据绑定问题,数据更新未触发界面刷新问题,以及一些页面上线前检查出的一些质量问题。

1.目的地首页数据分屏,界面未刷新 (关键词:复用,未触发界面更新)

问题描述:由于目的地页面数据来源复杂,所以数据一次吐出的话,耗时较长。所以首页数据分两次接口返回。但是实际操作下来,在第二次数据返回的时候,并没有触发界面更新。

问题解决:首页采用的是组件架构,每个Cell根据ModuleId列表里的Id去找到对应的模块进行渲染,条件为存在ModuleId对应的ModuleData(代码截图如下)。但是当第一次返回的时候,ModuleId列表被全量返回,虽然第二次返回了ModuleId列表里未被渲染的id对应的ModuleData被返回,但是ModuleId列表却没有发生变化,导致list组件的复用机制被触发,不会去触发界面重绘。

2.嵌套WebView带来的稳定性问题(关键词:嵌套WebView,稳定性)

关于这个问题,一句话解释:对于Web标签这种对应在Native上是浏览器的“重标签”。一定不要轻易生成,一定要等到具体使用时再去生成(使用if条件判断控件生成)!

3.目的地详情页Tab页数据完成绑定之后不显示,切换Tab回来的时候显示(关键词:二级数据,$set)

问题描述:玩法游记中有三个子tab,每个tab的接口返回数据放倒data的map里,接口返回数据之后设置对应的接口返回值,显示模块直接绑定的data['content-1'],data['content-2']等,这样绑定不会直接更新dom,后来增加一个list,存储当前的数据,data只作为缓存。数据绑定直接绑定list,这样就可以立即显示了。

问题解决:在Data下面的key,value里,如果value为list,直接修改list,是不会触发view update的。需要在list里,使用$set(index,’data’),来强制更新dom,完成view update。

这点其实在文档中有特别提醒:

NOTE: When you want to mutate an array in data. Something limitations existing below:

When you directly set an item with the index (vm.items[0] = {};), it won't trigger view update. So we have a prototype methods: $set(index, item).

// same as example1.items[0] = ... but triggers view update
example1.items.$set(0, { childMsg: 'Changed!'})
When you modify the length of the Array (vm.items.length = 0), it won't trigger view update too. We recommend you just replace items with an empty array instead.

// same as example2.items.length = 0 but triggers view update
example2.items = []


四.总结

为了开发人员一专多能,提能增效的目标。我们选择拥抱了Weex。对于我一个iOS开发来讲,Weex类Web开发的体验为了带来了很多Native开发上享受不到的便利。开放的技术世界-源码共享。无需繁琐的编译过程,hot-reload享受飞一般的感觉。同时Write once , Run anywhere的跨平台特性,大幅减少投入人日。这些无疑是我们会继续长期拥抱Weex的理由。但是同时作为一个尚在孩提时代的技术,它也存在了很多问题。比如三端不太一致,文档欠缺,组件还不是很丰富等。

但是去平台化永远去趋势,移动端技术之战还将不停的继续下去。Weex作为目前这个H5性能欠缺,而Native又拖累于发版节奏与封闭的时代是一个很好的解决方案。而Weex在当下也急需更多的业务方,更多的人去参与到Weex标准的世界,去证明自己的技术价值。希望Weex越来越好!

作者:唐笛_Dylan

链接:https://www.jianshu.com/p/a412296ab4b3