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

栏目: Html5 · 发布时间: 7年前

内容简介:最近接到上头的指示,要做一个体育类的小程序,并且要在元旦之前上线一版,看了下时间,距离元旦只有一个多月,而且除去测试的时间和双休,最多只有三个星期,时间相当的紧迫,而且需求文档都更新到1.3了,这也就意味着安卓和ios的版本迭代已经到了1.3了,而我们小程序要在三个星期内开发完1.0-1.3版本的功能,所以我们的时间相当的紧迫,看了下需求文档和原型图,我整个人大吃一惊,有100多个页面,我顿时懵逼了,产品经理更我说;你们只需做三个模块,最后一个模块不用做,我看了一下最后一个模块,有10几个页面,除去10几个

最近接到上头的指示,要做一个体育类的小程序,并且要在元旦之前上线一版,看了下时间,距离元旦只有一个多月,而且除去测试的时间和双休,最多只有三个星期,时间相当的紧迫,而且需求文档都更新到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('openId',data.unionId);
        },
        onGotUserInfo(e) {   //通过按钮触发getuserinfo
            if(e.mp.detail.userInfo){
                this.deCode(e.mp.detail.encryptedData,e.mp.detail.iv,this.sessionKey);
            }else{
                toast('请再次授权');
            }
        },
    }
复制代码

最终我们可以通过上面的代码获取 unionId解码地址下载 , 注意:解码这一步最好放在服务端解码,不要放在客户端解码,这样会造成信息泄露.....

  • 技术点2-在小程序中使用canvas

mpvue开发大型体育项目及总结记
mpvue开发大型体育项目及总结记
我们可以看到上面两个项目中的案例图片,他们是用canvas画的,第一个是采用微信官方的api, wx.createCanvasContext 不懂得同学可以自已去看 微信官方文档

,代码如下

const ctx = wx.createCanvasContext('myCanvas');
            ctx.setLineCap('round')
            var gradient1=ctx.createLinearGradient(0,0,170,0);
            gradient1.addColorStop("0","#FFF956");
            gradient1.addColorStop("1.0","#FF6C00");
            var gradient2=ctx.createLinearGradient(0,0,170,0);
            gradient2.addColorStop("0","#8156FE");
            gradient2.addColorStop("1.0","#3AFFF1");
            ctx.setLineWidth(4);
            ctx.beginPath();
            ctx.arc(50, 50, 30,0.75*Math.PI,0.25*Math.PI,false);
            ctx.setStrokeStyle('#4e4f59');
            ctx.stroke()
            ctx.beginPath();
            ctx.arc(50, 50, 38,0.75*Math.PI,0.25*Math.PI,false);
            ctx.setStrokeStyle('#4e4f59');
            ctx.stroke();
            //胜
            ctx.beginPath();
            ctx.arc(50, 50, 30,0.75*Math.PI,(((winarc*1.5+0.75)%2)==0?2:((winarc*1.5+0.75)%2))*Math.PI,false);
            ctx.setStrokeStyle(gradient1)
            ctx.stroke()
            //负
            ctx.beginPath();
            ctx.arc(50, 50, 38,0.75*Math.PI,(((failarc*1.5+0.75)%2)==0?2:((failarc*1.5+0.75)%2))*Math.PI,false)
            ctx.setStrokeStyle(gradient2);
            ctx.stroke()
            ctx.setTextAlign('center');
            ctx.setFontSize(16);
            ctx.setFillStyle('#fff');
            ctx.setTextBaseline('middle');
            ctx.fillText('战绩', 50, 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) {}
   }
   //注意:以上代码只是模拟,仅供查考。
复制代码
  • 技术点3-图片上传转化base64

图片上传微信小程序给我们提供了api, 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可以解决我们上面的问题,微信官方文档,代码如下

wx.chooseImage({
                count: 1,
                sizeType: ['original', 'compressed'],
                sourceType: ['album', '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  class="pickes"  mode="multiSelector" 
           @change="PickerChange"
           @columnchange="PickerColumnChange" 
           :range="allList" 
           range-key='provinceName'  
           :value='multiIndex' v-if='show'>
          <div class="slot"></div>
    </picker>
复制代码
/**
 * @describe 省市选择器
 * @rerurn  省,市,省id,市id
 */
  import {allCity} from "@/http/api.js";
  export default {
      data() {
        return {
            list:[],
            multiIndex: [0, 0], //显示化动的列数
            allList:[],    //存储二维数据
            singleList:[], //存储一维数组
            show:false,    //防止数据没有加载出来
            cityInfo:{},   //存储省,市,省id,市id
        }
      },
      mounted(){
        this.init();
      },
      methods:{
        async init(){   
            try {
                 let child=[],data=null;
                  data=await allCity();  //获取后台返回的城市
                  this.singleList=data.result;
                 child.push(data.result[0]);
                 this.allList.push(data.result,child);
                this.show=true;
            } catch (error) {}
        },
          PickerChange(e) {
             this.cityInfo.provinceId=this.singleList[e.mp.detail.value[0]].provinceId; //省id
             this.cityInfo.provinceName=this.singleList[e.mp.detail.value[0]].provinceName; //省名
             this.cityInfo.cityId=this.singleList[e.mp.detail.value[0]].cityList[e.mp.detail.value[1]].cityId; //城市id
             this.cityInfo.cityName=this.singleList[e.mp.detail.value[0]].cityList[e.mp.detail.value[1]].cityName; //城市名
             this.$emit('cityInfo',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;
                this.multiIndex[1]=0;  //注意这个表示的时选择中省切换的时候,要将省的第一个城市放在第一位
                break;
            }
          },
      }
  }
复制代码
mpvue开发大型体育项目及总结记
  • 技术点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('cityLocal','定位失败');
                        }
                    }
                })
        }
    });
复制代码
  • 技术点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>
复制代码
//注意我这里只列举城市索引选择的代码,有些代码省略了,请熟知。
   onPageScroll(e){
        this.scollTop=e.scrollTop    //同步
    },
    methods:{
         touStart(flag,text){
                 try {
                    wx.createSelectorQuery().select(flag).fields({   //运用微信节点api
                    dataset: true,
                        size: true,
                        rect: true,
                        computedStyle: ['margin', 'backgroundColor']
                        }, (res)=> {
                            wx.pageScrollTo({
                                    scrollTop: this.scollTop+res.top,
                                    duration: 0
                            });
                            this.on=true;
                            this.modalText=text;
                            setTimeout(()=>{
                                  this.on=false;
                            },2000)
                        }).exec() 
                 }catch (error) {}
            },
    }
复制代码
mpvue开发大型体育项目及总结记
当然实现上面这个功能也可以用其他的方法,如scroll-view,我这里就不多说了。
  • 技术点7-返回上一层页面,刷新页面数据

我们可以通过微信中的 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框架的介绍和使用

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

On LISP

On LISP

Paul Graham / Prentice Hall / 09 September, 1993 / $52.00

On Lisp is a comprehensive study of advanced Lisp techniques, with bottom-up programming as the unifying theme. It gives the first complete description of macros and macro applications. The book also ......一起来看看 《On LISP》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具