最近接到上头的指示,要做一个体育类的小程序,并且要在元旦之前上线一版,看了下时间,距离元旦只有一个多月,而且除去测试的时间和双休,最多只有三个星期,时间相当的紧迫,而且需求文档都更新到1.3了,这也就意味着安卓和ios的版本迭代已经到了1.3了,而我们小程序要在三个星期内开发完1.0-1.3版本的功能,所以我们的时间相当的紧迫,看了下需求文档和原型图,我整个人大吃一惊,有100多个页面,我顿时懵逼了,产品经理更我说;你们只需做三个模块,最后一个模块不用做,我看了一下最后一个模块,有10几个页面,除去10几个页面还有90多个呀,页面还好,最难的是需求文档的业务逻辑呀,而且这个项目的难度比中小型电商项目类的要难的多,交互相当的频繁和复杂,怎么办呢,一句话,凉拌,毕竟这是boss要求做的项目,只好硬着头皮往下做,不得不从。
技术选型
因小程序页面多,切交互频繁,如果用原生开发的话,时间来不急,而且页面的交互很多,这样原生小程序就显得那么的吃力了,最终我将技术选型放在了,wepy和mpvue这两个框架上,wepy框架是微信官方维护的,兼容性和扩展性很好,mpvue是美团旗下的,我最终选择了mpvue,原因是mpvue的语法跟Vue的语法是一样的,而且我们的前端同学都会Vue,所以选择mpvue是最好的选择,于是看了一下mpvue的文档和注意点,最终搭建了小程序的项目结构,将任务安排了下去,于是开启了加班的苦日子....
技术点1-小程序,安卓,iOS三端数据信息同步,免登陆
因项目中的登录方式含有微信登录,所以三端协商,如果用户是微信登录的话,三端统一取, unionid
这个字段,这时肯定有同学要问;为什么不取 openid
,如果做过小程序的人一定知道openid是唯一的标识,微信小程序有一个,那么在安卓,iOS他们也都有自已的openid标识,所以这样是不能达到三端数据信息同步,免登陆的效果的,微信官方介绍了6种获取 unionid
的方法,我们项目最终采用了解密获取的方法,官方文档。
import {AchieveOpenid} from '@/http/api.js';
let that=this;
wx.login({
async success(resCode){
const cache=await AchieveOpenid({ //openid,内部服务器=》腾讯获取到了openid
code:resCode.code
});
that.openid=cache.result.unionid;
wx.setStorageSync('openId',that.openid);
}
})
复制代码
注意:这个方法是官方中的wx.login+code2Session方法,也确实可以获取unionid,但是天有不测风云呀,测试组的人员测出了unionid不存在的情况,而且还有几个账号也出现了这种问题,那么我们就开始找原因,最终我们发现,如果用户没有关注过任何的公众号,微信是不会给他返回unionid的,我们找到原因之后,马上换了另外一种方法,那就是解码的方式,也是我们最终的方法。
<button class='openpage-authorize'
open-type="getUserInfo"
lang="zh_CN"
@getuserinfo="onGotUserInfo">
</button>
复制代码
//注意我这里只列举解码的代码,有些代码省略了,请熟知。
import WXBizDataCrypt from "@/utils/cryptojs/RdWXBizDataCrypt.js" //引用解码
methods:{
deCode(encryptedData,iv,sessionKey){
let wxObj=null,data=null;
wxObj= new WXBizDataCrypt('wx3ea59bf3ff3a9bb8',sessionKey);
data= wxObj.decryptData(encryptedData,iv);
this.openid=data.unionId;
wx.setStorageSync(data.unionId);
},onGotUserInfo(e) { //通过按钮触发getuserinfo
if(e.mp.detail.userInfo){
this.deCode(e.mp.detail.encryptedData,e.mp.detail.iv,51); font-weight: 700;">this.sessionKey);
}else{
toast('请再次授权');
}
},}
复制代码
最终我们可以通过上面的代码获取 unionId
, 解码地址下载 , 注意:解码这一步最好放在服务端解码,不要放在客户端解码,这样会造成信息泄露.....
技术点2-在小程序中使用canvas
wx.createCanvasContext
不懂得同学可以自已去看 微信官方文档,代码如下
);
ctx.setLineCap('round')
var gradient1=ctx.createLinearGradient(0,170,0);">0);
gradient1.addColorStop("0","#FFF956");
gradient1.addColorStop("1.0",0);">"#FF6C00");
var gradient2=ctx.createLinearGradient(0);
gradient2.addColorStop("#8156FE");
gradient2.addColorStop("#3AFFF1");
ctx.setlinewidth(4);
ctx.beginPath();
ctx.arc(50,0);">30,0);">0.75*Math.PI,0);">0.25*false);
ctx.setstrokeStyle('#4e4f59');
ctx.stroke()
ctx.beginPath();
ctx.arc(38,0);">'#4e4f59');
ctx.stroke();
//胜
ctx.beginPath();
ctx.arc(1.5+0.75)%2)==0?2:((winarc*2))*false);
ctx.setstrokeStyle(gradient1)
ctx.stroke()
//负
ctx.beginPath();
ctx.arc(2:((failarc*false)
ctx.setstrokeStyle(gradient2);
ctx.stroke()
ctx.setTextAlign('center');
ctx.setFontSize(16);
ctx.setFillStyle('#fff');
ctx.setTextBaseline('middle');
ctx.fillText('战绩',0);">50);
ctx.draw()
复制代码
注意点:如果canva的数据是异步的话,一定要在数据加载完成之后,在让它渲染到视图层中去,如果不这样做的话,canvas会数据不同步,具体的做法可以加一个开关,如下..
<canvas canvas-id="myCanvas" class="index-header-data-circle-canvas" v-if='on'></canvas>
复制代码
data(){
return {
on:false
}
}
async xx(){
try{
const data=await xxx();
this.on=data.code==='000'?true:false;
}catch (error) {}
}
//注意:以上代码只是模拟,仅供查考。
复制代码
图片上传微信小程序给我们提供了api,249); border: 0px; font-weight: 600; font-size: 14px;'>wx.chooseImage ,上传简单,关键是如何转化base64位呢,我们的舒同学用了如下的写法,看着确实没什么问题,用临时路径作为一个请求的url,把数据返回格式设置成arraybuffer,这个也确实是个办法,在微信开发工具里面也是ok的,但是天有不测风云呀,在真机上请求报错了,那么这种方法pass掉。
wx.chooseImage({
success:res=>{
wx.request({
url:url,responseType: 'arraybuffer',//最关键的参数,设置返回的数据格式为arraybuffer
success:res=>{
let base64 = wx.arrayBufferToBase64(res.data);
}
})
})
复制代码
针对上面的问题,仔细的看了下微信官方文档,最终找到了一个代码少,简单的方法, wx.getFileSystemManager()
这个api可以解决我们上面的问题,微信官方文档,代码如下
,0);">'compressed'],sourceType: ['album',0);">'camera'],success:(res)=>{
wx.getFileSystemManager().readFile({
filePath:res.tempFilePaths[0],//选择图片返回的相对路径
encoding: 'base64',success: res => {
console.log(res.data)
}
})
}
})
复制代码
其实除了, wx.getFileSystemManager()
可以解决我们的问题外,还有一种方法,那就是更html5一样的处理方法,通过canvas来画,然后在用canvas的api来转base64, 注意:如果通过canvas来转base64的话,有个bug,那就是在iOS手机上图片会出现旋转90度的问题
小程序可以借鉴 这个同学的方法来解决 ,如果是html5的话可以通过 exif.js 这个库来解决问题。
技术点4-对picker的封装
小程序中有个picker组件,他支持5中类型,虽然有5中类型但是每个项目的不同,所以对picker的用途就不同,因此我们将对picker进行封装,来达到满足我们项目的需求,我们封装省市,时间日期等组件,我这里就只介绍 省市
组件的封装,其他的组件封装原理同省市组件原理一样的,我这里就不多说了,代码如下。
<picker "pickes" mode="multiSelector"
@change="PickerChange"
@columnchange="PickerColumnChange"
:range="allList"
range-key='provinceName'
:value='multiIndex' v-if='show'>
<div "slot"></div>
</picker>
复制代码
,51); font-weight: 700;">this.cityInfo); //将值传给父组件
},PickerColumnChange(e) {
switch (e.mp.detail.column) {
case 0:
this.list = [];
this.singleList.forEach(item => {
if (item.provinceId ==this.singleList[e.mp.detail.value].provinceId) {
item.cityList.forEach(item=>{
//注意这一步最为重要,给数组添加一个和父对象一样的键值名,这样picker组件可以找的到
item.provinceName=item.cityName;
})
}
});
this.allList[1]=this.list;
this.multiIndex[0]=e.mp.detail.value;
1]=0; //注意这个表示的时选择中省切换的时候,要将省的第一个城市放在第一位
break;
}
},}
}
复制代码
技术点5-在小程序使用高德定位
因项目中要用到定位功能,而小程序中的的api并不适用项目,所以就选择了高德定位,高德小程序版文档,代码如下
//注意我这里只列举定位的代码,有些代码省略了,请熟知。
let _this = this,myAmapFun=null;
myAmapFun = new amapFile.AMapWX({
key: "xxxxx" //高德的密钥
});
myAmapFun.getRegeo({
success(data){
_this.$store.dispatch('cityLocal',data[0].regeocodeData.addressComponent.city);
},fail(err) {
wx.showModal({
title: '提示',content: '定位失败,请手动定位',success (res) {
if (res.confirm) {
path({url:'/pages/city/main'});
}else if (res.cancel) {
_this.$store.dispatch('定位失败');
}
}
})
}
});
复制代码
技术点6-对微信小程序节点的运用
由于项目用到了城市索引选择功能,所以就采用 wx.createSelectorQuery()
这个api来实现这个功能,代码如下
<ul class="slide">
<li v-for="(item,index) in cityJson.leter"
:key="index"
@tap='touStart(item.letid,item.lettext)'>
{{item.lettext}}
</li>
</ul>
复制代码
,0);">'backgroundColor']
},(res)=> {
wx.pageScrollTo({
scrollTop: this.scollTop+res.top,duration: 0
});
this.on=true;
this.modalText=text;
setTimeout(()=>{
false;
},0);">2000)
}).exec()
}catch (error) {}
},}
复制代码
当然实现上面这个功能也可以用其他的方法,如scroll-view,我这里就不多说了。
我们可以通过微信中的 wx.navigateBack()
这个api就可以返回上一层页面,但是怎样返回上一层页面并且刷新呢,其实可以通过onShow这个生命周期函数来刷新页面,如果那个页面含有参数的话,最好代码这么写
onShow(){
//之所以用try,是因为mpvue官方说,如果要获取地址参数的话,最好在mounted周期里面获取,我们用try可以避免代码终止和报错
try {
let id=this.$root.$mp.query.Id;
this.init(id);
}catch (error) {}
}
复制代码
结语
由于时间的原因,我暂时先介绍这几个在小程序中常见的问题和功能,后面我会陆续介绍,如下技术栈
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。