微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

mpvue开发大型体育项目及总结记

最近接到上头的指示,要做一个体育类的小程序,并且要在元旦之前上线一版,看了下时间,距离元旦只有一个多月,而且除去测试的时间和双休,最多只有三个星期,时间相当的紧迫,而且需求文档都更新到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 , 解码地址下载 , 注意:解码这一步最好放在服务端解码,不要放在客户端解码,这样会造成信息泄露.....

我们可以看到上面两个项目中的案例图片,他们是用canvas画的,第一个是采用微信官方的api,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;
            }
          },}
  }
复制代码

因项目中要用到定位功能,而小程序中的的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('定位失败');
                        }
                    }
                })
        }
    });
复制代码

由于项目用到了城市索引选择功能,所以就采用 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) {}
}
复制代码

结语

由于时间的原因,我暂时先介绍这几个在小程序中常见的问题和功能,后面我会陆续介绍,如下技术栈

  • vue的三种ssr方法,以及在项目中的使用
  • react+redux在项目中的使用
  • 打造自已的webpack,gulp开发环境
  • koa框架的介绍和使用

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。