Uniapp 多端开发经验整理

文档说明:

本文档目的在于帮助基于 Uniapp 进行移动开发的人员 快速上手、规避问题、提升效率。将以流程提纲的方式,整理开发过程各阶段可能出现的问题点以及思路。对官方文档中已有内容,会贴附链接,尽量不做过多阐述以免冗余。

使用时可根据需求和自身掌握情况,从目录跳转查看。

Uniapp 使用 Vue 语法+微信小程序 API,有二者基础可快速上手,开发 APP 还会用到 HTML5+规范 ,有非常丰富的原生能力。在此还是建议尽量安排时间通读官方文档,至少留下既有功能的印象,来增强对 Uniapp 开发的掌握,游刃有余的应对各类开发需求。

<br/><br/>

开发准备

<br/>

小程序

后台配置

  • 小程序个别类目需要行业资质,需要一定时间来申请,根据项目自身情况尽早进行 服务类目 的设置以免影响上线时间。

  • 必须在后台进行 服务器域名配置,域名必须 为 https 。否则无法进行网络请求。注意 每月只有 5 次修改机会

    在开发工具中可配置不验证 https,这样可以临时使用非 https 接口进行开发。非 https 真机预览时需要从右上角打开调试功能。

  • 如果有 webview 需求,必须在小程序管理后台配置域名白名单。

开发工具

  • 下载 微信开发者工具
  • 设置 → 安全 → 打开“服务端口”。打开后方可用 HbuilderX 运行并更新到微信开发者工具。

<br/>

APP

证书文件

  • 准备苹果开发账号

  • ios 证书、描述文件 申请方法

    证书和描述文件分为开发(Development)和发布(Distribution)两种,Distribution 用来打正式包,Development 用来打自定义基座包。

    ios 测试手机需要在苹果开发后台添加手机登录的 Apple 账号,且仅限邮箱方式注册的账号,否则无法添加。

<br>

Uniapp

创建 Uni-app 项目

根据 文档 操作即可,新建时建议先不选择模板,因为模板后期也可以作为插件导入。这里推荐一个 UI 框架 uView,兼容 Nvue 的 Uniapp 生态框架。

路由

  • 配置: 路由的开发方式与 Vue 不同,不再是 router,而是参照小程序原生开发规则在 pages.json 中进行 配置,注意 path 前面不加"/"。

  • 跳转: 路由的 跳转方式,同样参照了小程序 有 navigator 标签API 两种。

    1. navigator 标签: 推荐使用 有助于 SEO(搜索引擎优化)。
    2. API: 常用跳转方式 uni.navigateTo()uni.redirectTo()uni.switchTab(),即可处理大部分路由情况。

    需注意:

    • tabBar 页面 仅能通过 uni.switchTab<navigator open-type="switchTab"></navigator>方法进行跳转。
    • 如需求特殊可以自定义开发 tabBar,即 pages.json 中不要设置 tabBar,这样也就不需要使用 uni.switchTab 了。
    • url 前面需要加"/"
  • 问题点: 小程序页面栈最多 10 层。也就是说使用 uni.navigateTo 最多只能跳转 9 层页面。

    解决: 这里不推荐直接使用 uni.redirectTo 取代来处理,会影响用户体验,除非产品设计如此。建议在会出现同页面跳转的页面(例:产品详情 → 点击底部更多产品 → 产品详情 →...),封装一下页面跳转方法,使用 getCurrentPages() 方法获取当前页面栈的列表,根据列表长度去判断使用什么路由方法。路由方法的选择根据实际情况决定 官方文档

    //页面跳转
    toPage(url){
     let pages=getCurrentPages()
     if(pages.length<9){
     uni.navigateTo({url})
     }else{
     uni.redirectTo({url})//根据实际情况选择路由方法
     }
    }

分包加载

提前规划好分包,使代码文件更加规整,全局思路更加清晰。可以根据业务流程或者业务类型来设计分包。官方文档

  • 分包加载的使用场景:

    1. 主包大小超过 2m。
    2. 访问落地页启动较慢(因为需要下载整个主包)。
  • 分包优化:

    除页面可以分包配置,静态文件、js 也可以配置分包。可以进一步优化落地页加载速度。

    manifest.json对应平台下配置 "optimization":{"subPackages":true} 来开启分包优化。开启后分包目录下可以放置 static 内容。

    //manifest.json源码
    {
     ...,
     "mp-weixin" : {//这里以微信为例,如有其他平台需要分别添加
     ...,
     "optimization" : {
     "subPackages" : true
     }
     }
    }
  • 分包预载

    通过分包进入落地页后,可能会有跳转其他分包页面的需求。开启分包预载,在落地页分包数据加载完后,提前加载后续分包页面,详见 官方文档

生命周期

  • Uniapp 的页面生命周期建议使用 onLoadonShowonReadyonHide 等,也可以使用 vue 生命周期 createdmounted 等,但是组件的生命周期仅支持vue 生命周期的写法。

easycom 组件模式

  • 说明: 只要组件安装在项目的 components 目录下或 uni_modules 目录下,并符合 components/组件名称/组件名称.vue 的目录结构,就可以不用引用、注册,直接在页面中使用。

    easycom 为默认开启状态,可关闭。可以根据需求配置其他路径规则。详见 官方文档

  • 代码举例:

    非 easycom 模式

    <template>
     <view>
     <goods-list></goods-list>
     </view>
    </template>
    <script>
    import goodsList from '@/component/goods-list'; //引用组件
    export default {
     components: {
     goodsList //注册组件
     }
    };
    </script>

    使用 easycom 模式

    <template>
     <view>
     <!-- 无需引用、注册,直接使用组件即可-->
     <goods-list></goods-list>
     </view>
    </template>
    <script>
    export default {};
    </script>

是否使用 Nvue

  • Nvue 开发
    • 优点:原生渲染,性能优势明显(性能优势主要体现在长列表)、启用纯原生渲染模式( manifest 里设置 app-plus 下的 renderer:"native" ) 可进一步减少打包体积(去除了小程序 webview 渲染相关模块)
    • 缺点:与 Vue 开发存在 差异,上手难度相对较高。并且设备兼容性问题较多。
    • 使用:适合仅开发 APP,并且项目对性能有较高要求、组件有复杂层级需求的情况下使用。
  • Nvue+vue 混合开发
    • 优点:性能与开发难度折中的选择,即大部分页面使用 Vue 开发,部分有性能要求的页面用 Nvue 开发。
    • 缺点:同 Nvue 开发。并且当应用没有长列表时,与 Vue 开发相比性能提升不明显。
    • 使用:适合需要同时开发 APP+小程序或 H5,并且项目有长列表的情况下使用。
  • Vue 开发
    • 优点:直接使用 Vue 语法进行开发,所有开发平台皆可兼容。
    • 缺点:在 APP 平台,使用 webview 渲染,性能比较 Nvue 相对差。
    • 使用:适合除需要 Nvue 开发外的所有情况。如果 APP 没有性能要求可使用 vue 一锅端。

跨域

  • 如需开发 H5 版本,本地调试会碰到跨域问题。

  • 3 种解决方案:

    1. 使用 HbuilderX 内置浏览器预览。内置浏览器经过处理,不存在跨域问题。

    2. manifest.json 中配置,然后在封装的接口中判断 url

      // manifest.json
      {
       "h5": {
       "devServer": {
       "proxy": {
       "/api": {
       "target": "https://***.***.com",
       "pathRewrite": {
       "^/api": ""
       }
       }
       }
       }
       }
      }
      //判断当前是否生产环境
      let url = (process.env.NODE_ENV == 'production' ? baseUrl : '/api') + api;
    3. 创建一个 vue.config.js 文件,并在里面配置 devServer

      // vue.config.js
      module.exports = {
       devServer: {
       proxy: {
       '/api': {
       target: 'https://***.***.com',
       pathRewrite: {
       '^/api': ''
       }
       }
       }
       }
      };

      如果 2、3 方法同时使用,2 会覆盖 3。

一键登录

  • 5+APP 一键登录,顾名思义:使用了 HTML5+规范、仅 APP 能用。官方指南
  • 小程序、H5 没有 HTML5+扩展规范。小程序可以使用 <button open-type="getphonenumber"> 并结合微信开发文档 实现一键获取手机号。

推送

既然在 uniapp 生态,就直接使用 UniPush 推送服务。

  • 该服务由个推提供,但必须向 DCloud 重新申请账号,不能用个推账号。

<br>

<br>

开发中

<br/>

CSS

  • 建议使用 flex 布局开发。因为 flex 布局更灵活高效,且便于适配 Nvue(Nvue 仅支持 flex 布局)。

  • 小程序 css 中 background 背景图不支持本地路径。解决办法改为网络路径或 base64。

  • 图片设置 display:block。否则图片下方会有 3px 的空隙,会影响 UI 效果。

  • 多行文字需要限制行数溢出隐藏时,Nvue 和非 Nvue 写法不同。

    Nvue 写法

    .text {
     lines: 2; //行数
     text-overflow: ellipsis;
     word-wrap: break-word;
    }

    非 Nvue 写法

    .text {
     display: -webkit-box;
     -webkit-line-clamp: 2; //行数
     -webkit-box-orient: vertical;
     overflow: hidden;
     text-overflow: ellipsis;
    }

<br>

图片

mode

  • Uniapp 的 <image> 与传统 web 开发中的 <img> 相比多了一个 mode 属性,用来设置图片的裁剪、缩放模式。

  • 在开发中尽量养成每一个 <iamge> 都设置 mode 的习惯。可以规避掉很多 UI 显示异常的问题

  • 一般只需要使用 widthFixaspectFill 这两个属性即可应对绝大多数情况。

    即只需设置宽度自动撑起高度的图片用 widthFix ;需要固定尺寸设置宽高,并保持图片不被拉伸的图片用 aspectFill

    例如:所有 icon、文章详情里、产品详情里的详情图一般会用 widthFix,用户头像、缩略图一般会用 aspectFill

    属性详情见 官方文档

lazy-load

  • 图片懒加载,小程序支持,只针对 page 与 scroll-view 下的 image 有效。

<br/>

图片压缩

  • 静态图片未压缩。该问题不限于 Uniapp 开发,也包括其他开发方式。是非常常见的问题。

  • 图片压缩前后,包体大小可差距 50%甚至更多。对编译和加载速度提升显著!

  • 此处放上两个 在线压缩工具 自行取用:Tinypngiloveimg

<br/>

滚动穿透

  • 弹窗遮罩显示时,底层页面仍可滚动。给遮罩最外层 view 增加事件 @touchmove.stop.prevent

    <view class="pop-box" @touchmove.stop.prevent></view>

<br>

底部安全区

  • 问题: iOS 全面屏设备的屏幕底部有黑色横条显示,会对 UI 造成遮挡,影响事件点击和视觉效果。Android 没有横条,不受影响。

  • 场景: 各页面底部悬浮菜单、相对于底部距离固定的悬浮按钮、长列表的最后一个内容。

  • 解决方案:

    • 使用 css 样式 constant(safe-area-inset-bottom)env(safe-area-inset-bottom) 来处理,兼容 iOS11.2+,根据 iOS 系统版本占比,可放心使用。需注意该方法小程序模拟器不支持,真机正常。

      <template>
       <view class="bottomBar"></view>
      </template>
      <style>
      .bottomBar {
       /*
       关于使用constant(safe-area-inset-bottom)、env(safe-area-inset-bottom)
       会返回底部安全区的高度
       两个方法都写,会自动选择能够生效的来使用
       可以使用calc方法来计算,根据实际情况灵活使用
       */
       padding-bottom: calc(0rpx + constant(safe-area-inset-bottom));
       padding-bottom: calc(0rpx + env(safe-area-inset-bottom));
      }
      </style>
    • 如果使用 nvue,则不支持以上方案。可使用 HTML5+规范 的方法来处理。

      <template>
       <view :style="{ paddingBottom: `${holderHeight}px` }"></view>
      </template>
      <script>
      export default{
       data(){
       return{
       /***
       * 先判断是否iOS,再判断是否刘海屏即全面屏。34即为底部安全高度
       * plus.os.name返回系统平台名称,plus.navigator.hasNotchInScreen()返回是否是刘海屏。
       * 一定要先判断是否iOS,因为该问题仅iOS需处理,而且Android返回是否刘海屏标准不一,会有显示问题。
       */
       holderHeight:plus.os.name == 'iOS' ? (plus.navigator.hasNotchInScreen() ? 34 : 0) : 0)
       }
       }
       }
      </script>

<br/>

交互反馈

移动端比 PC 画面小很多,但是要展示的内容并不少,甚至更多。为了让用户正常使用,并获得优良体验。交互反馈的设置是必不可少的。并且在 UI 设计评审时就应该确定好,所有交互反馈是否齐全。

  • 缺省样式: 所有数量可能为空的数据展示,都应添加缺省样式,乃至缺省样式后的后续引导。

    例如:评论区没有评论,不应显示空白,而是显示(具体按 UI 设计):一个 message 的 icon,下方跟一句"快来发表你的高见",下方再跟一个发表按钮。这样不仅体现了评论区的状态,还做了评论的引导,增加了互动概率。

  • 状态提醒: 所有需要时间相应的状态变化,或者逻辑变化。都应对用户提供状态提醒。同样需要在 UI 设计评审时确认。

    例如:无网络时,显示网络异常,点击重试。各种等待、 下拉刷新、上拉加载、上传、下载、提交成功、失败、内容未加载完成时的骨架屏。甚至可以在点赞时加一个 vibrateShort 等等。

<br>

分享

除非特别要求不分享,或者订单等特殊页面。否则在开发时各个页面中一定要有设置分享的习惯。可以使应用的功能更完整更合理并且有助于搜索引擎优化。是必须考虑但又容易忽略的地方。

  • 在页面的生命周期中添加 onShareAppMessage 并配置其参数,否则点击右上角三个点,分享相关按钮是不可点击状态。

  • 小程序可以通过右上角胶囊按钮或者页面中 <button open-type='share'> 按钮来触发 分享功能

  • 代码示例:

    <template>
     <!-- 假如这是一个社区列表页面 -->
     <view v-for="(item, index) in list">
     <button open-type="share" :data-item="item">分享</button>
     </view>
    </template>
    <script>
    export default{
     data(){
     return{
     //列表数据
     list:[
     {
     id:1,
     title:"标题",
     img:'***.jpg'
     }
     ]
     }
     },
     onShareAppMessage(){
     // 点击页面中分享按钮,这样可以分别设置分享内容
     if (res.from === 'button') {
     let item=res.target.dataset.item
     return {
     title: item.title,
     path: `/pages/detail?id=${item.id}`,
     imageUrl:item.img
     }
     }
     //点击右上角胶囊按钮分享的设置
     return {
     title: '**社区',
     path: '/pages/community/'
     }
     }
    }
    </script>
  • return 的 Object 中 imageUrl 必须为宽高比例 5:4 的图片,并且图片大小尽量小于 20K。imageUrl 可不填,会自动截取当前页面画面。

  • 另外 button 有默认样式,需要清除一下。

    <template>
     <button class="btn-share" open-type="share"></button>
    </template>
    <style lang="scss">
    .btn-share {
     padding: 0;
     margin: 0;
     border: 0;
     &::after {
     padding: 0;
     margin: 0;
     border: 0;
     }
     /*以上代码完成了样式清除,接下来写新的css样式*/
    }
    </style>

<br/>

获取用户手机号

  • 小程序通过点击 button 获取 code 来跟后端换取手机号。在开发者工具中无法获取到 code。真机预览中可以获取到。

    <template>
     <button open-type="getPhoneNumber" @getphonenumber="getphonenumber">
     获取用户手机号
     </button>
    </template>
    <script>
    export default {
     methods: {
     getphonenumber(e) {
     let code = e.detail.code; //开发工具中无法获取到该code,用真机预览进行测试
     //开发阶段可以设置剪贴板将code复制。便于跟后端对接调试。调试完成后记得删除。
     uni.setClipboardData({
     data: e.detail.code
     });
     }
     }
    };
    </script>

<br>

苹果登录

  • APP 苹果登录需要使用自定义基座打包才能获得 Apple 的登录信息进行测试

  • iOS 自定义基座打包需要用开发(Development)版的证书和描述文件

<br>

H5 唤起 App

两种实现方式:

  1. URL Sheme

    优点:配置简单

    缺点:会弹窗询问“是否打开***”,未安装时网页没有回调,而且会弹窗“打不开网页,因为网址无效”;微信微博 QQ 等应用中被禁用,用户体验一般。

  2. Universal Link

    优点:没有额外弹窗,体验更优。

    缺点:配置门槛更高,需要一个不同于 H5 域名的 https 域名(跨域才出发 UL);iOS9 以上有效,iOS9 一下还是要用 URL Sheme 来解决;未安装 App 时会跳转到 404 需要单独处理。

<br><br>

打包发布

<br/>

摇树优化

  • H5 打包时去除未引用的组件、API。

  • 摇树优化(treeShaking)

    //manifest.json
    "h5" : {
     "optimization":{
     "treeShaking":{
     "enable":true //启用摇树优化
     }
     }
    }

<br>

启动图标

让 UI 帮忙切一个符合以下标准的图片,在 APP 图标配置中自动生成即可。

  • 格式为 png
  • UI 切图时不要带圆角
  • 分辨率不小于 1024×1024

<br>

启动图

  • 如没有特殊要求,直接使用通用启动页面即可。

  • 如需自定义启动图:

    • Android 可直接使用普通 png,也可配置.9.png,可减少包体积,避免缩放影响清晰度。为了更好的效果和体验建议使用.9 图。

      如何制作.9.png?使用 Android studio、ps。或者找 UI 同事帮忙

    • iOS 需要制作storyboard,如所需效果与 uni 提供的 storyboard 模板类似,可直接使用模板修改代码即可(xml 格式)。否则需要使用 xcode 进行更深度的修改,以实现效果并适配各机型。

<br>

权限配置

HBuilderX 默认会勾选一些不需要的权限,为避免审核打回,需要注意以下权限配置

  • manifest.json 中的【App 权限配置】取消勾选“Android 自动添加第三方 SDK 需要的权限”,然后在下方配置处根据参考文档取消勾选没有用到的权限,额外注意核对推送、分享等功能的权限需求。
  • manifest.json 中的【App 模块配置】仅勾选所需模块(容易漏掉,也会影响权限)

<br><br>

补充

SEO(搜索引擎优化)

用户流量是衡量产品的重要指标之一,受到很多方面影响,SEO 就是其中之一。在没有额外推广的情况下,搜索引擎带来的流量基本就是产品流量的主要来源。传统 web 开发通过设置 TDK、sitemap 等,现阶段移动开发方法有所变化,但是万变不离其宗,核心还是一样的。

  • 小程序:

    • 被动方式:
      1. 确保 URL 可直接打开,通俗说就是 url 要有效,不能是 404。
      2. 页面跳转优先采用 navigator 组件
      3. 清晰简洁的页面参数
      4. 必要的时候才请求用户进行授权、登录、绑定手机号等
      5. 不收录 web-view,若非不需 seo 内容(用户协议之类)、或已有 H5 页面节省开发,否则尽量不要用 web-view。
      6. 配置sitemap
      7. 设置标题和分享缩略图 类似于传统 web 中设置 TDK。在百度小程序中有专门的接口来传递 SEO 信息。
    • 主动方式:
      1. 使用页面路径推送能力让微信收录内容

    内容详情请查看 优化指南。所有被动方式可以作为开发习惯来养成。

  • H5: 因为 Uniapp 是基于 Vue 语法来开发,这种 SPA 对于 SEO 并不友好。业界有 SSR(服务端渲染) 方法,等了很久 Uniapp 官方也终于提供了 SSR 的方法,但是需要使用 uniCloud。所以如果没有使用 uniCloud,暂时没有更合适的方法来处理该问题。

  • APP: 方式脱离前端范畴,不做讨论。

作者:Tigger

%s 个评论

要回复文章请先登录注册