本意

听闻2018将是小流程暴发的两年,或许是固步自封吧,做为一位后端初学者,我也已经开始玩了小流程,从原本在提前布局看自己写的小流程工程项目,到现如今不经意他们玩儿了两个月,也想做点小东西权当,只好有了那个小工程项目。

工程项目如是说

去年,青桔电单车登入了我所处的卫星城,外型简洁风尚,再说是不光讨厌。正好我又在科学研究小流程,只好想品雅版两个青桔电单车小流程的后端同时实现,小厂的工程项目却是很牛逼的,有许多提高新体验的技术细节,值得称赞自学,我也在当中转化成了许多他们的设想,整体而言,我指出共享电单车类小流程,只不过新体验还能做得更快。

在那个工程项目操作过程中,踩了挺多坑的,很值得称赞纪录下来。只好措词,将我同时实现操作过程的诸多,做为撷取,期望能协助到许多老师。

演示电单车创下

撸两个『升级版青🍊电单车』插图

抹除功能定位

撸两个『升级版青🍊电单车』插图1

推论距近电单车

撸两个『升级版青🍊电单车』插图2

点选电单车手动方向总体规划

撸两个『升级版青🍊电单车』插图3

快捷方式电话号码手动拆分

撸两个『升级版青🍊电单车』插图4

演示登入

撸两个『升级版青🍊电单车』插图5

演示扫码骑行

撸两个『升级版青🍊电单车』插图6

结束骑行并支付

撸两个『升级版青🍊电单车』插图7

Github源码地址:升级版青 电单车有需要的欢迎fork ,如果讨厌,请给个Star

具体内容

接下来是具体内容如是说

目录结构

● ┣━ config 存放伪造数据的mock ┣━ images 图片素材 ┣━ libs 引入的高德地图SDK ┣━ pages ● 页面 ┣━ init //主界面 ┣━ login //登入界面 ┣━ userCenter //个人中心 ┣━ messageCenter //消息中心 ┣━ unlock //解锁 ┣━ charge //计价 ┣━ end //结束行程 ┣━ repair //电单车报修 ┗━ record //行程记录 ┣━ utils ┣━ app.js ┣━ app.wxss ┣━ app.json ┗━ project.config.json

构建和谐一致的地图主界面

撸两个『升级版青🍊电单车』插图8

主界面很简洁,上部分为两个map组件,下方为两个扫码解锁按钮,map组件中有三个小控件,一条横幅。看起来挺简单吧,但是想要做出这样的界面,得先稍思考一下。

map组件堪称小流程复杂的两个组件,它是由客户端创建的原生组件,并且它的层级是高的,不能通过 z-index 控制层级。这句话意味着,普通组件,无法覆盖在它的上方。不过cover-view和cover-image组件例外,接下来要用到。

更多技术细节能查看map组件的官方文档map组件

使用弹性布局,安排上方地图,底部扫码解锁按钮

实测发现,青桔电单车的底部按钮并非button组件,而是使用view组件 不过是添加了许多样式。底部按钮的高度是固定的,使用相对单位rpx。在不同的设备上,map组件高度要能跟据设备的屏幕高度手动拉伸或者收窄,而不影响到显示效果。使用弹性布局是佳的解决方案,只要设置下方按钮flex:1,上方自适应即可。

使用cover-image打造新体验和谐的控件

我们能使用map组件得controls 做制作控件。也能使用cover-image来制作。

新体验了一下其他的地图类小流程,发现大部分的地图控件使用了map组件的controls来制作,controls控件自带按压的交互效果,但是只能使用图片,无法设置样式,且它们的宽高大小单位默认是px,在不同设备上,实际新体验很诡异。

青桔电单车使用cover-image是来制作覆盖在地图表面的控件,在样式中通过rpx相对单位来设置控件大小,这能带来令人舒心的效果,不仅如此,这几天突然发现官方文档更新了,cover-image以后将完全代替controls

撸两个『升级版青🍊电单车』插图9

在map组件上做出阴影效果

在开发地图首页的操作过程中,令我印象深刻的莫过于此了,毕竟这深深折磨过我好长一段时间。随意举两个例子,先来看看这些小流程中的效果。

撸两个『升级版青🍊电单车』插图10撸两个『升级版青🍊电单车』插图11

有没有阴影效果,对于实际使用而言,完全没有任何影响,但或许这是后端吧,即使在map组件上同时实现起来各种坑,后端开发者都得去想办法同时实现,正如雷布斯说过得那句话:因为我们是工程师。哪怕它的实际新体验只能好百分之一,我们都愿意付出百分之九十九的努力。

前面有讲到map组件的层级高。这也是坑的一点。起初我天真地以为使用cssbox-shadow属性能搞定,坑爹的开发者工具中确实也会显示出阴影效果,但是一到真机测试,所有的阴影都会被map组件覆盖,尝试了各种方法无果,而cover-view和cover-image能够支持的css样式又只有简单的几种,想要在map组件上使用css做出阴影效果基本上是不可能的。

目前解决方案只有两个,是使用cover-image,添加一张能覆盖在map组件之上的图片来演示阴影。实际上,这些小厂都是这样做的。

分析完了上述的问题,我们能顺利做出那个主界面的效果,附上主页的wxml你会明白怎么做了,样式具体同时实现方法能查看我的源码

{{topText}} 扫码解锁

为地图添加功能定位功能

小流程为我们提供了很多好用的API,开发时能去查看小流程API

撸两个『升级版青🍊电单车』插图12

只需要调用一下wx.getLocation(OBJECT)那个API能很轻松地获取到当前所处位置

wx.getLocation({ type: gcj02, success: (res) => { let longitude = res.longitude; let latitude = res.latitude; this.setData({ longitude, latitude }) })

做出新体验良好的地图交互

地图类小流程中,map组件上主要地交互,莫过于抹除功能定位那个按钮

抹除功能定位功能同时实现起来很简单,只需要先创建两个map上下文,再调用moveToLocation()API能同时实现

onReady() { // 创建map上下文 保存map信息的对象 this.mapCtx = wx.createMapContext(myMap); }

在使用摩拜电单车小流程地时候,如果缩放过地图视野,那么每次抹除功能定位后,都要再去手动缩放地图寻找电单车,因为电单车扎堆在一起了

撸两个『升级版青🍊电单车』插图13

在青桔电单车中,新体验好多了,抹除功能定位后,也会抹除地图视野地缩放级别,能很快速推论附件电单车位置,同时实现方法很简单,只需要在抹除功能定位后设置1s后调回缩放比

toReset(){ //调回缩放比,提高新体验 setTimeout(()=>{ this.setData({ scale: 18 }) },1000) this.mapCtx.moveToLocation(); }

这也是两个小小的技术细节,地图类的小流程都能用得上,同时实现的效果如下,那个新体验很酷

撸两个『升级版青🍊电单车』插图1

写两个随机函数来生成伪造电单车

为了同时实现许多更加高级的功能,我不得不做许多假数据,来演示更加逼真的新体验。

我简单的写了两个方法用来在当前功能定位的坐标点附件随机生成一批电单车。

tocreate(res) { // 随机电单车数量设置 这里设置为1-20辆 let ran = Math.ceil(Math.random() * 20); let markers = this.data.markers; for(let i = 0; i < ran; i++) { // 定义两个临时电单车对象 var t_bic = { “id”: 0, “title”:去这里, “iconPath”: “/images/map-bicycle.png”, “callout”:{}, “latitude”: 0, “longitude”: 0, “width”: 52.5, “height”: 30 } // 随机 var sign_a = Math.random(); var sign_b = Math.random(); // 电单车分布密集度设置 var a = (Math.ceil(Math.random() * 99)) * 0.00002; var b = (Math.ceil(Math.random() * 99)) * 0.00002; t_bic.id = i; t_bic.longitude = (sign_a > 0.5 ? res.longitude + a : res.longitude – a); t_bic.latitude = (sign_b > 0.5 ? res.latitude + b : res.latitude – b); markers.push(t_bic); } //将演示的电单车数据暂时存储到本地 wx.setStorage({ key: bicycle, data: markers }) this.setData({ markers }) }

接在来只要在map组件的bindregionchange事件中调用伪造电单车的函数行了

撸两个『升级版青🍊电单车』插图14

bindregionchange事件能在map视野发送变化时触发,但是我不期望地图稍作移动会创下电单车,所以还需要简单演示一下移动创下电单车的阈值

regionchange(e){ // 拿到起点经纬度 if(e.type == begin) { this.mapCtx.getCenterLocation({ type: gcj02, success: (res) => { this.setData({ lastLongitude: res.longitude, lastLatitude: res.latitude }) } }) } // 拿到当前经纬度 if (e.type == end) { this.mapCtx.getCenterLocation({ type: gcj02, success: (res) => { let lon_distance = res.longitude – this.data.lastLongitude; let lat_distance = res.latitude – this.data.lastLatitude; // console.log(lon_distance,lat_distance) // 推论屏幕移动距,如果超过设定的阈值,演示创下电单车 if (Math.abs(lon_distance) >= 0.0035 || Math.abs(lat_distance) >= 0.0022){ console.log(创下电单车) this.setData({ // 创下电单车之前先清空原来的电单车 markers: [] }) this.tocreate(res) } } }) } }

这样,做出了如下的效果

撸两个『升级版青🍊电单车』插图

同时实现推论距近电单车的功能

你们应该早发现,地图上的电单车中,距近的那辆电单车头上会有离我近两个小气泡。那个是检索出近的电单车的功能,摩拜电单车同时实现了那个功能,可是青桔电单车官方并没有加入那个小的新体验,以后应该也会有吧。这里我尝试去同时实现了一下

同时实现逻辑

遍历当前地图上的每一辆电单车和中心坐标点的距,存到两个数组中遍历数组,找出当中的最小值,并返回最小值的索引在最小值的索引对应的电单车中添加气泡提示
nearestBic(res) { // 找出最近的电单车 let markers = this.data.markers; let min_index = 0; let distanceArr = []; //存放电单车距的数组 for (let i = 0; i < markers.length; i++) { let lon = markers[i].longitude; let lat = markers[i].latitude; // 计算距 sqrt((x1-x2)^2 + (y1-y2)^2 ) let t = Math.sqrt((lon – res.longitude) * (lon – res.longitude) + (lat – res.latitude) * (lat – res.latitude)); let distance = t; // 将每一次计算的距加入数组 distanceArr distanceArr.push(distance) } //从距数组中找出最小值 let min = distanceArr[0]; for (let i = 0; i < distanceArr.length; i++) { if (parseFloat(distanceArr[i]) < parseFloat(min)) { min = distanceArr[i]; min_index = i; } } let callout = “markers[” + min_index + “].callout”; // 清除旧的气泡,设置新气泡 wx.getStorage({ key: bicycle, success: (res) => { this.setData({ markers: res.data, [callout]: { “content”: 离我最近, “color”: “ffffff”, “fontSize”: “16”, “borderRadius”: “50”, “padding”: “10”, “bgColor”: “0082FCaa”, “display”: ALWAYS } }) } }) }

将那个函数在每次创下电单车和map视野改变的时候调用,能看到如下的效果了,详细调用操作过程请移步源码

撸两个『升级版青🍊电单车』插图2

同时实现手动选中电单车手动总体规划步行至方向

嗯。。。那个功能我觉得却是有必要的,在许多场景中会遇到。

比如:我想骑车,眼前没有车。或者只有一辆车,打开微信扫码,这时糟糕的结果出现了:该电单车暂时无法使用。我却是想骑车,不想走路,地图的功能就发挥作用了,我会查看地图附近别的电单车,这时候看到了许多电单车,但是得走一段路才能找到它,如果能点一下这辆电单车,就手动总体规划步行的路线就好了。

只好乎,我大胆地做了两个同时实现,如下图

撸两个『升级版青🍊电单车』插图3

接下来讲讲,怎么去同时实现它

想要同时实现手动方向总体规划的功能,他们去同时实现基本上不可能,我们需要借助第三方强大的力量来做到。

引入高德地图SDK

首先不知道你会不会这样想:What?腾讯地图里面用高德SDK?

这没有什么不能的,在微信小流程中,不论是百度地图、高德地图、却是腾讯地图,都为小流程专门提供了Javascript SDK

高德地图微信小流程 SDK 能协助我们在小流程中获取到丰富的地址描述、POI和实时天气数据,以及同时实现地址解析和逆地址解析等功能,非常强大,不过这里我们只需要使用到它方向总体规划的功能

高德地图微信小流程SDK

腾讯地图和百度地图都没有为微信小流程提供手动方向总体规划的功能,所以高德地图却是很贴心的。

想要使用它,必须前往高德地图开放平台进行注册,获取到他们的key,详细的步骤在高德地图微信小流程SDK入门指南中如是说得很清楚

SDK下载地址

下载好后把它解压,在工程项目目录新建两个libs文件夹把它放进去

撸两个『升级版青🍊电单车』插图15

接着在需要用到得js文件顶部引入

var amapFile = require(../../libs/amap-wx.js); var myAmapFun = new amapFile.AMapWX({ key: 你的key });

有了它,能写两个专门负责规则方向得方法

route(bic){ // 获取当前中心经纬度 this.mapCtx.getCenterLocation({ success: (res) => { // 调用高德地图步行方向总体规划API myAmapFun.getWalkingRoute({ origin: `${res.longitude},${res.latitude}`, destination: `${bic.longitude},${bic.latitude}`, success: (data) => { let points = []; if (data.paths && data.paths[0] && data.paths[0].steps) { let steps = data.paths[0].steps; for (let i = 0; i < steps.length; i++) { let poLen = steps[i].polyline.split(;); for (let j = 0; j < poLen.length; j++) { points.push({ longitude: parseFloat(poLen[j].split(,)[0]), latitude: parseFloat(poLen[j].split(,)[1]) }) } } } // 设置map组件polyline,绘制线路 this.setData({ polyline: [{ points: points, color: “ffffffaa”, arrowLine:true, borderColor: “3CBCA3”, borderWidth:2, width: 5, }] }); } }) } }) }

微信小流程map组件提供了polyline属性,它能在map组件上方跟据设置好的点来绘制方向

撸两个『升级版青🍊电单车』插图16

方向的颜色和样式都能设置,哇~简直有点酷

在这里,为了致敬青桔电单车,我尽量的把方向的风格做得青桔电单车相似,然后我们再来回顾一下效果

撸两个『升级版青🍊电单车』插图17

打造新体验良好的登入界面

地图主界面打理好了,接下来写一下登入界面吧。

登入页面看似简单,但是想要做出两个新体验不错的登入界面,实际同时实现起来,里面的逻辑却是蛮多的

手动拆分电话号码

在青桔电单车小流程中,发现了这样两个小技术细节,快捷方式中输入的电话号码会手动进行拆分,感觉这是两个不错的用户新体验,拆分显示的电话号码,能使得输入操作过程中的错误一目了然,看起来更爽

撸两个『升级版青🍊电单车』插图4

为了模仿出那个新体验,我按照他们的逻辑去同时实现了它。

我的同时实现逻辑思路1. 电话号码码都是11位的,分为三段XXX空格XXXX空格XXXX,我们在第3次输入和第7次输入的数字后追加空格,那不能同时实现那个效果了么2. 因为加入了两个空格,所以设置快捷方式大长度为13位3. input的value属性绑定到逻辑层的data中的定义的phoneText,之后能用js来改变它的显示重要!!4. 设置bindinput属性,让每次输入都执行一下input 函数

“““

我写了那个input方法来同时实现电话号码的拆分

input(e) { let value = e.detail.value; //正则过滤 value = value.replace(/[\u4E00-\u9FA5`~!@$%^&*()_+<>?:”{},.\/;[\]\-\sa-zA-Z]*/g, “”); let result = []; for (let i = 0; i < value.length; i++) { if (i == 3 || i == 7) { result.push(” “, value.charAt(i)); } else { result.push(value.charAt(i)); } } this.setData({ phoneText: result.join(“”) }) }
注:不过为了做出那个效果,却是做出许多了妥协,那就是不能调用微信内置的数字键盘输入。否则将会看不到那个拆分的效果

只不过使用微信内置的键盘,能很方便的规避掉非法字符的输入,也是数字以外的字符,如:英文字母,标点符号等。

按钮 可用&不可用 逻辑

在快捷方式未完成基本的填写之前,按钮应该是不可用的,验证码快捷方式应该要做隐藏,待用户填写完之后,验证码快捷方式出现,验证码输入完毕后按钮亮起,这样的设定应该更加符合用户的心理暗示

那个页面,涉及到两个按钮获取验证码以及下一步和 两个清楚快捷方式图标- 电话号码快捷方式应是不能输入非数字以外的字符的,虽然这里肯定不会存在xss,但是为了严谨,却是用正则来过滤一下- 当快捷方式中存在内容的时候,清除内容按钮出现,清空内容后,清除内容按钮消失,所有按钮不可用- 在电话号码码填写完后,获取验证码按钮变为可用状态,验证码快捷方式出现- 电话号码码和验证码同时满足填写条件后,下一步按钮变为可用状态- 点选下一步,或者获取验证码时,要校验电话号码码是否正确-同时实现效果如下,具体同时实现代码请移步源码

撸两个『升级版青🍊电单车』插图18
撸两个『升级版青🍊电单车』插图19
撸两个『升级版青🍊电单车』插图5

扫码解锁功能

同时实现扫码解锁,只需要调用小流程的wx.scanCode()那个API,能调用相机的扫码功能,当然,扫码之前先进行登入检查,若未登入,切换到登入界面,由于只是后端功能的同时实现,所以扫码后直接跳转到解锁界面

toScan(){ if (!app.globalData.loginStatus) { wx.showModal({ title: 提示, content: 请先登入, success: (res) => { if (res.confirm) { wx.navigateTo({ url: /pages/login/login }) } } }) } else { wx.scanCode({ success: (res) => { onlyFromCamera: false, console.log(扫码成功); wx.navigateTo({ url: /pages/unlock/unlock, }) } }) } }

解锁后进入骑行状态,效果如下:

撸两个『升级版青🍊电单车』插图6

骑行状态下,只显示当前骑行车辆,并在车辆上方添加气泡,表明骑行中

骑行计费

共享电单车计费都是跟据使用时长来推论的,由于没有后端数据,这里也只能写两个计时器方法Time()来演示计费

Time(){ let s = 0; let m = 0 // 计时已经开始 this.timer = setInterval(() => { this.setData({ second: s++ }) if (s == 60) { s = 0; m++; setTimeout(() => { this.setData({ minute: m }); }, 1000) }; }, 1000) }

当骑行已经开始时,调用计时器,已经开始计时,点选结束骑行,计时器停止,跟据时长计价,并跳转到支付页面

撸两个『升级版青🍊电单车』插图7

结语

因为时间比较短,工程项目有许多功能还未加入,也有许多待改进的地方,后续会抽时间慢慢打磨,如果你有更快的设想,也能联系我一起完善。

后,附上我的工程项目地址:升级版青 电单车

有需要的欢迎fork ,如果讨厌,请给个Star

作者 nasiapp

在线客服
官方客服
我们将24小时内回复。
12:01
您好,有任何疑问请与我们联系!

选择聊天工具: