TOPLIFE是京东旗下独立运营的全生态精品电商,集创新尊崇的用户体验与领先的电商布局于一身,致力于打造奢侈品牌的线上精品旗舰,成为中国新精英消费者的精致生活指南。
简介太长了,关键词“独立”,“全生态”,“精品”,“领先”,独立意味着全新一套体系,可以抛弃祖传代码;全生态,则是APP之后就是M站,PC站,小程序,未来还可能是快应用或者……
在TOPLIFE PC站上我们使用了Nerv,Nerv在完美兼容React语法的同时,具有着出众的性能表现,在Gzip后也只占用9Kb的体积。最重要的是按React的方式再加ESLint+Husky,让团队里的其他成员随时参入这个项目来撸码,人力抽走的时候别的同学轻易接手,参与过PC站的开发有10来个同学,一切是那么完美和谐。
TOPLIFE PC之后,得知3月份就要进入小程序开发,那时候还在迭代PC站,匆忙之间还是把小程序文档和wepy文档看了一遍。至于为什么使用wepy而不是直接写原生代码呢,因为轮子总是比双脚走得快一些,而且还是这么多人在使用的轮子呢,就它了。
嘿嘿,其实没有那么草率啦,大概以下那么几点:
- 有同学使用过wepy来做过自研项目,有一些积累,其推荐使用
- 支持使用第三方 npm 资源
- 支持ES2015
- 支持样式编译器:Less/Sass/Styus
- 腾讯家出的,他自家好多业务都使用
有时候其实不需要太多理由,因为可以选择的本来就很少,mpvue,wepy,原生小程序。
上手撸小程序比较简单:
- 申请账号,根据指引填写信息和提交资料,开通账号
Toplife小程序最后的目录大致的如下:
.
├── actions
│ └── index.js
├── app.wpy
├── asset
│ └── toplife_icon.png
├── components
│ ├── gb
│ │ └── popup.wpy
├── constants
│ └── apis.js
├── pages
│ └── index.wpy
├── reducers
│ └── index.js
├── store
│ └── index.js
└── utils
└── util.js
一个页面是这样的
<style lang="scss">
.container { ... }
.index_list { ... }
.index_brands_go {...
&_hover { ... }
}
</style>
<template>
<view class="container">
<view class="index_list">
...
</view>
</view>
<button @tap="goToBrandList" class="index_brands_go" hover-class="index_item_go_hover"></button>
</view>
</template>
<script>
import wepy from 'wepy'
import { connect } from 'wepy-redux'
import { fetchIndexList } from '../actions/index'
@connect({
homeData (state) {
return state.home
}
}, {fetchIndexList})
export default class Index extends wepy.page {
config = {
navigationBarTitleText: 'TOPLIFE',
enablePullDownRefresh: true,
backgroundTextStyle: 'dark'
}
data = {
shouldIndexHidden: false
}
methods = {
async goToBrandList () {
await wepy.navigateTo({
url: './brand/brand_list'
})
}
}
onShareAppMessage (options) { ... }
async onLoad (options) {
// 填充首页的数据
await this.methods.fetchIndexList()
}
onShow () { ... }
onReady () { ... }
}
</script>
简单介绍一下这个版本吧,大概就只有9个页面,产品的定位是用于营销,所以就比较简单了,首页、品牌页、店铺页、文章页、登陆相关的页面,现在回忆起来好像很简单,比较麻烦的就是首页里还有一个浮层页,浮层页里可以操作发新人券;还有就是文章页,有一个签到三天和七天发放优惠券的功能。
虽然简单几个页面,考虑到后续扩展,本来想简单撸撸地我们还是使用了数据流管理,采用Redux,有个wepy-redux,上面的目录结构就知道了。
接口放在了constants
文件夹下的api.js
里,图片放在asset
文件夹里。
在撸业务的过程中印象比较深刻的是以下一些问题:
- 登陆功能,这一部分代码从账号体系的同学手里给过来的,热乎的原生代码,zip格式的压缩包啊,热乎得很,我把它转化成wepy的形式顺便请教他好像有几个地方参数对不上,他也改得迅速,改完那个文件直接扔过来,我接住还得问他是只改了X地方吗?两次之后挺麻烦的,索性建了个项目扔内部git平台上,他再更新代码我就对比一下看哪里改动了,其实他们要是搞个NPM包或者上传内部git多方便呀。
- 首页,显示的两种不同的banner,但是链接可能有三种,我直接wx:if三个判断,结果就是IOS9下出现了一些不兼容的情况,一些banner重复显示。改一些
wx:if
和wx:elif
,wx:else
就好了。 - 文章页,从首页到文章页或者店铺页,如果之前访问过就会发现,进来先是显示上一个页面,接着才被刷成当前页面,这里需要在上一个页面卸载的时候把数据清一下。
- 小程序生命周期的问题,页面(onReady)里命名和组件(ready)里的不一致,也许是为了区分,但对于刚上手来说还是需要费一些力气去记的。
- 小程序请求默认超时时间和最大超时时间都是60s,不能自己定义。
- 组件化,支持ES6/7,支持NPM,支持LESS预编译,开发起来很方便
- 第一次使用的时候发现编译后引用的某个包没有到dist目录里,手工复制了,但别的机器好像没有这个问题,神奇。
- 像Vue一样写代码,上手很简单。
- 原生的代码改成wepy的代码还是挺方便的,也支持混用。
- 把WXML、WXSS、JS 放在一个.wpy文件里,搜索和修改起来还是挺方便,很直观,以致于后来转换到Taro的时候一时没有适应过来。
- 事件绑定:@tap=“function”; function写在methods方法集合中,这点我也挺喜欢的,感觉看其他同学的代码舒服了。
- 脏数据处理带来一些好处,但触发脏数据检测的
wepy.$apply()
在写动画的时候会带来一些困扰。 - 经过两年积累,一些问题也是可以在issue里找到答案。
两三周搞定版本1.0以后,四月中旬产品就已经把二期排上了,说要5月中旬搞定,定位也变了,不再是一期的营销和导流,要形成闭环,同时还要联合奢侈品牌做一些合作活动。 购物的黄金流程、品牌店铺、活动页、个人中心、五月大促活动、埋点上报,当时的感觉是要一个月搞定很困难,和产品商量后,砍掉了部分需求,剩下的必做的,但是心里还是没有多少底气,终须一拼,boss说给5个人一起做。 彼时初出茅庐的Taro一脉相承于Nerv,未试牛刀,而之前toplife PC版使用了Nerv开发,大家都熟悉了像react一样开发,现在说要5个人一起开发小程序,那当然是Taro啦。 最后我们成功上线了,有时候从事后往回看,并不能说明孰是孰非,在向着目标行进的两条路上的不同风景而已。
.
├── actions
│ └── index.js
├── app.js
├── app.scss
├── asset
│ └── toplife_icon.png
├── components
│ └── gb
│ └── popup
│ ├── popup.js
│ └── popup.scss
├── constants
│ └── apis.js
├── pages
│ └── index.js
│ ├── index.js
│ └── index.scss
├── reducers
│ └── index.js
├── store
│ └── index.js
└── utils
└── util.js
import Taro, { Component, eventCenter } from '@tarojs/taro'
import { View, Image, Button } from '@tarojs/components'
import { connect } from '@tarojs/redux'
import './index.scss'
import { jumpUrl, gotoPage } from '../../utils/util'
import { fetchIndexList } from '../../actions/index'
class Index extends Component {
config = {
navigationBarTitleText: 'TOPLIFE',
enablePullDownRefresh: true,
backgroundTextStyle: 'dark'
}
constructor() {
super(...arguments)
this.state = {
shouldIndexHidden: false
}
this.$app = this.$app || {}
}
onShareAppMessage (options) { ... }
async onPullDownRefresh() { ... }
async componentWillMount() {
// 填充首页的数据
await this.props.fetchIndexList()
}
componentDidMount() { ... }
componentDidShow () { ... }
componentWillUnmount () { ... }
render () {
const { shouldIndexHidden } = this.state
const { homeData } = this.props
return (
<View className={indexClassNames}>
...
</View>
)
}
}
export default connect(({ home }) => ({
homeData: home
}), (dispatch) => ({
fetchIndexList() {
dispatch(fetchIndexList())
}
}))(Index)
文件目录上看还是比较清晰的,同V1的时候没有太多的区别,只是增加了很多页面,这里为了方便,我简化了。 个人开始比较喜欢.wpy单文件,后期文件比较长的时候我就很纠结了,把样式从头部放到了尾部,切到Taro后,倒是不用纠结了。
首先是迁移问题,1.0的时候使用了Wepy,比较规范,整个迁移过程还是比较顺畅的,一两天就搞定了。2.0版成功地试水发布后,另一个内部项目玲珑小程序的开发者决定从wepy迁移到了Taro,11个页面大概用了3天。
关于迁移的意义,如果是从原生到Wepy或者Taro,个人还是觉得值得的,毕竟带来了一些方便,但同时也会带来一些问题,毕竟框架自己也有一些坑,但他们都比较成熟稳定的话,那还是很完美的。单纯从Wepy迁移到Taro,如果你不是更喜欢React或者想同时生成H5,写Wepy或者Taro都是差不多的。
第一版的时候使用了redux,第二版业务要搞复杂很多,也不用去重构第一版的代码,所以一贯不怕麻烦是可以省去很多麻烦的。大家都会react,几个人开发上手还是比较快的。
和第一版一样很多页面还是需要在页面unload的时候去reset数据,要不返回后再进入会先显示上次访问的数据,然后再渲染成这次的数据,这个是Wepy和Taro都会有的,而使用原生小程序没有这个问题。
这一版toplife后台接口验证了Referer
,小程序不允许改Referrer
,开发者工具里是https://servicewechat.com/{appid}/devtools/page-frame.html
,线上是https://servicewechat.com/{appid}/{version}/page-frame.html
。
整个项目几乎是输出一些页面就提测,几乎和测试同学并行,在开发过程中还是有一些顾及不到的地方只能等发布后再优化了。
- 同样是支持组件化和可以使用NPM包及ES 6/7语法,支持样式编译器,开发起来很便利。
- 页面和组件统一的生命周期,不用去理会页面是
onReady
而组件是ready
这种细节。 - 从像Vue一样开发小程序到像React一样开发小程序,个人还是喜欢react一些,Taro使用React的生命周期,例如
componentDidMount
使得小程序的页面onReady
和组件的ready
接口统一了,不用费心去记,上手难度低了一些,很方便有React基础的同学加入项目里。 - 获取页面的参数在Taro里使用
this.$router.params
这个对象,例如/pages/detail?id=543
则是this.$router.params.id
就可以拿到了543
,在小程序里好像就只能在onLoad
里的option
取到了,例如:
Page({
onLoad: function(option){
console.log(option.id)
}
})
- Taro引用组件的时候都是大写开头的,例如
Image
,在写样式的时候如果想用标签应该是使用image
,不过个人觉得还是取个类名会比较明智一下,万一以后改标签呢。 - Taro对不支持的语法和特性单独写了 ESLint 规则,我们只管写代码,写到不支持的语法/特性编辑器会报错,并给出报错信息和一个文档地址描述。
- 因为是试水,所以Taro还是会遇到一些问题的,不过好在反馈后,主创们一顿操作猛如虎,版本更新快得飞起,没有影响到开发进度。我们开发的toplife第二版完成的时候,taro的版本是0.0.39,现在已经是0.0.60,这速度也是没谁了。
有些人觉得前端变化太快了,前些日子deno出来的时候,一人去刷deno的issue「求不要更新了,老子学不动了」,想来可笑。Toplife我们尝试了很多东西,从PC使用Nerv到小程序使用Wepy,然后又是Taro,在永远做不完的需求面前,至少是越来越愉悦了,开发越来越便利了,代码越来越规范,合作比以前轻松,接手别人的代码也没有以前那么抗拒了。
现在写小程序的框架还是非常多的,我们实践过的taro
、wepy
,以及没有试过的mpvue
、tina
,都为了让我们更快更爽地搞定需求,早点回家陪家人,或者世界杯年的时候可以有时间早点回家看球。
要写小程序,选一个框架肯定比直接写原生小程序方便,如果你手里恰好有把锤子(会react或vue),那么选择相应的加强工具taro或wepy。如果想一套代码多端使用,那必然是taro了,目前小程序和H5都支持了,下一步是RN和快应用。
最后如果有同学问我“如果要在wepy和taro中选择一个,选择哪个呢?”我的回答是taro。“如果是你的最好的朋友要这众多的框架中推荐一个呢?” 答案还是一样的。