uni-app初体验

274 阅读4分钟

近期由于公司业务扩展,组织架构调整,小程序需要进行重构。而之前的小程序区分了微信端和支付宝端,分别采用原生语言进行开发。虽然开发起来很方便,各自使用各自的api,但是最大的问题就是几乎所有的逻辑都需要cv两遍,同时如果有需求迭代,两边都需要进行修改,改动多的话很有可能会出现遗漏的问题。因此这次重构就决定使用多端转换,一套代码搞定。

在框架选择上,开始定位了两个框架,taro和uni。taro在之前公司使用过,是偏向react语法,当时在开发过程中遇到了某些卡死流程的问题,最后不得不用原生重新开发了一遍,因此本人对于taro没有太大的好感。而uni采用vue语法,文档和社区也都相对活跃,因此决定采用uni开发,直接转微信和支付宝两个小程序。

具体开发流程就不细说了,相关api也都和微信小程序的差不太多,只不过前缀换成了uni.,不太了解的小伙伴可以查看文档uni-app文档,本文主要说一些开发过程中的小问题点。

一、关于环境判断

这个内容基本是开发过程中不可或缺的内容,任何项目和框架开发最基本都会区分开发和生产环境,uni的区分也很大众化,直接用 NODE_ENV 就可以处理。

const isDev = process.env.NODE_ENV === 'development'

二、应用类型判断

就是区分当前环境是在微信小程序、支付宝小程序还是在APP内部,因为个别方法可能会有区别,开发过程中通常是需要进行环境区分。这里分为两种方法(此处主要以微信、支付宝小程序为例):

方法一:比较基础的写法,注意前边的 // 是必备的
// #ifdef MP-WEIXIN
    consoel.log('这是微信小程序')
// #endif

// #ifdef MP-ALIPAY
    console.log('这是支付宝小程序')
// #endif

方法二:整合法,通常开发中经常会用到区分环境,如果都像方法一那样就很麻烦,可以直接定义一个变量去判断
export function checkMp(){
    let mpType = ''
    // #ifdef MP-WEIXIN
    mpType = 'wx'
    // #endif
	
    // #ifdef MP-ALIPAY
    mpType = 'ali'
    // #endif
    return mpType
}

三、关于小程序自定义导航栏

在需求中设计小姐姐经常会设计沉浸式的样式,看上去特别炫,这就需要小程序端设置沉浸式导航,同时可能需要自己开发导航栏。

// 微信小程序只需要设置: "navigationStyle":"custom" 即可。
// 支付宝小程序需要单独配置:
"mp-alipay":{
    "titlePenetrate":"YES",
    "transparentTitle":"auto",
    "allowsBounceVertical": "NO"
}

按照上述配置,可以实现沉浸式和自定义导航的效果。但是支付宝小程序让人🤮的问题又出现了,跳转进入页面后原自带的返回箭头是不会隐藏也没办法去掉的!!!对此,支付宝官方给出的方法是,使用my.hideBackHome() 隐藏掉,当然也没有更好的办法。

顺便贴一下自定义导航栏代码,有需要的小伙伴们可以cv大法走起~

<template name="Nav">
    <view class="nav-wrap" :class='navbarData.isBg ? "bgWhite" : ""' :style="{height: height + 'px'}">
    <!-- 不用原生状态栏,状态栏占位符 -->
    <view :style="{height: statusHeight + 'px'}"></view>
    <!-- 标题栏 -->
    <view class="title_wrap">
        <!-- 导航栏标题 -->
        <view class='nav-title' :class="navbarData.isTitleWhite ? 'nav-title-white' : ''" :style="{height: titleHeight + 'px', lineHeight: titleHeight + 'px'}">{{navbarData.title}}</view>
            <view  :style="{height: titleHeight + 'px'}">
                <!-- 导航栏  左上角的返回按钮 和home按钮 -->
                <view class='nav-capsule' :style="{height: titleHeight + 'px'}" v-if='navbarData.showCapsuleBack'>
                    <!-- 从分享进入小程序时 返回上一级按钮不应该存在 -->
                    <view @click='_navback' v-if='!navbarData.share'>
                        <image v-if="navbarData.isTitleWhite" src='../../static/nav_back_white.jpg' mode='aspectFill' class='back-pre' />
                        <image v-else src='../../static/nav_back.png' mode='aspectFill' class='back-pre' />
                    </view>
                </view>
                <view class='nav-capsule' :style="{height: titleHeight + 'px'}" v-if='navbarData.showCapsuleNav'>
                    <view @click='_backhome' class="nav_home_icon">
                        <image v-if="navbarData.isTitleWhite" src='../../static/nav_home_white.png' mode='aspectFill' class='back-home' />
                        <image v-else src='../../static/nav_home.png' mode='aspectFill' class='back-home' />
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>

<script>
export default {
    name: "Nav",
    props: {
        //默认值  默认显示左上角
        navbarData: {
          isBg: false,   // 是否有背景色
          isTitleWhite: false,  // 是否为白色标题
          title: '',  // 导航标题
          showCapsuleNav: 0,  // 是否是首页按钮,默认false
          showCapsuleBack: 0,  // 是否有返回箭头,默认false
          share: false  // 默认不是分享
        }
    },
    data() {
        return {
            height: 0,
            titleHeight: 0,
            statusHeight: 0,
        }
    },
    mounted() {
        this.height = getApp().globalData.navHeight
        this.titleHeight = getApp().globalData.titleBarHeight
        this.statusHeight = getApp().globalData.statusBarHeight
        
        // 支付宝小程序自定义头部,返回按钮不会隐藏
        // #ifdef MP-ALIPAY
        setTimeout(()=>{
            uni.hideBackHome()
        }, 500)
        // #endif
    },
    methods: {
        // 返回上一页面
        _navback() {
            uni.navigateBack()
        },
        //返回到首页
        _backhome() {
            uni.redirectTo({
                url: '../../pages/index/index'
            })
        }
    }
}
</script>

<style scoped>
.nav-wrap {
    position: fixed;
    width: 100%;
    top: 0;
    color: #000;
    z-index: 9999999;
}
.bgWhite{
    background: #FFCA00;
}
.title_wrap{
    width: 100%;
    position: relative;
}
/* 标题要居中 */
.nav-title {
    position: absolute;
    text-align: center;
    max-width: 400rpx;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    font-size: 36rpx;
    color: #2c2b2b;
    font-weight: 600;
}
.nav-title-white{
    color: #fff;
}
.nav-capsule {
    display: flex;
    align-items: center;
    margin-left: 30rpx;
    width: 140rpx;
    height: 100%;
}
.back-pre, .back-home {
    width: 32rpx;
    height: 36rpx;
    margin-top: 4rpx;
}
.nav-capsule .back-home {
    width: 40rpx;
    height: 40rpx;
    margin-top: 3rpx;
}
</style>

四、关于小程序授权手机号

uni开发小程序授权手机号,微信和支付宝可以使用同一个方法,直接上代码

<button hover-class="btn-hover" class='phone_re_btn' open-type="getPhoneNumber" @getphonenumber="getPhoneRecharge">点击授权</button>

;; methods方法:
getPhoneRecharge(e){
    //需要获取当前选择的权益
    if (e.detail.errMsg == 'getPhoneNumber:ok') {
      // 同意授权逻辑
    } else {
      // 拒绝授权
      console.log('充值拒绝授权====>', e)
    }
}

五、关于小程序授权用户信息

uni开发小程序,授权用户信息,针对微信和支付宝小程序,需要区分开来进行触发。

<button v-if="checkMp === 'wx'" class="index_head_name" hover-class="btn-hover" @click="getUserInfo">微信授权用户信息</button>
<button v-else-if="checkMp === 'ali'" class="index_head_name" hover-class="btn-hover" scope="userInfo" open-type="getAuthorize" @getAuthorize="onGetAuthorize" @error="onAuthError">支付宝授权用户信息</button>

// methods方法:

// 支付宝小程序需要调用按钮方法,里边调用授权方法
// #ifdef MP-ALIPAY
onGetAuthorize(){
    this.getUserInfo()
},
onAuthError(err){
    console.log('支付宝拒绝授权===>', err)
},
// #endif

getUserInfo(res){
    let that = this
    if(this.checkMp === 'wx'){
        if(wx.canIUse('getUserProfile')){
            uni.getUserProfile({
                lang: 'zh_CN',
                desc:'微信用户信息',
                success(res){
                    console.log('wx userinfo success', res)
                    if (res.errMsg == 'getUserProfile:ok') {
                      // 拿到用户信息逻辑
                    }
                },
                fail(err){
                    console.log('wx err', err)
                }
            })
        } else {
            // 不出现授权层直接获取
            uni.getUserInfo({
                lang: 'zh_CN',
                desc:'微信用户信息',
                success(res){
                    console.log('wx userinfo success', res)
                    if (res.errMsg == 'getUserProfile:ok') {
                      // 拿到用户信息逻辑
                    }
                },
                fail(err){
                    console.log('wx err', err)
                }
            })
        }
    } else if(this.checkMp === 'ali') {
        uni.getUserInfo({
            lang: 'zh_CN',
            success(res){
                console.log('zfb userinfo success', res)
                let userInfoData = JSON.parse(res.response).response; 
                // 解析两层 response,获取用户信息
                // 注意支付宝的用户性别获取的是m、f的字符串,而非0、1值
            },
            fail(err){
                console.log('zfb userinfo err', err)
            }
        })
    }
}

以上就是对uni-app的初体验,整体开发完觉得并没有太大的问题,如果是熟悉vue和小程序原生的小伙伴们开发起来会相当便捷。同时代码一键转换,只需要处理个别平台间的差异即可。完全可以实现一套代码多端使用。