uni-app(一):初体验

1,339 阅读10分钟

本篇文章,是正式分享 uniapp 开发体验的第一篇。将会从技术选型开始,尽量全面得介绍 uni 的开发过程。如有不足,欢迎评论区交流指出。🎉

项目背景

当前应用 uni 的项目,是一个类似于百度网盘的软件,包含了手机浏览器端(h5)、手机移动应用端(Android)、微信小程序端(听产品经理的意思,后续还需要钉钉小程序😑)。
主要功能都是围绕文件管理设计的,包括文件上传、文件下载、文件预览、文件在线编辑、文件关键词扫描等等。。。
考虑到功能繁多,加上有多个终端需要支持,所以放弃了开发维护多套原生代码的选择,直接奔着跨端方案去了。

技术选型

社区的跨平台方案其实不少,比如 flutter、react native、uni-app 等等。但是为什么最终选择了 uni 呢?主要原因有以下几个:

  • 项目并没有很高的性能要求(toB 项目)
  • 我更擅长 vue 技术栈🐶
  • 需要涵盖小程序端
  • 时间紧、任务重(没错,领导给了我两个月时间,并且从始至终我都是一个人在战斗😭)

项目搭建

uni 的项目搭建不可谓不简单,得益于 HBuilderX 图形化界面,几秒钟就可以生成本地项目框架。附上官网教程。当然,除了图形化界面,uni 也支持 cli 命令搭建项目,出于工期压力,我并没有去细致了解,感兴趣的同学可以去官网学习一下。

通过图形化界面初始化项目是可以选择模板的,HBuilderX 提供了多个模板,我个人是选择了 uni-ui 模板,当然你也可以选择空白模板。uni-ui 是官方提供的一套 UI 组件库,我个人的宗旨是,既然都使用跨端框架了,能用官方提供的轮子,尽量选择官方出品的。

项目结构

附上官网上的一张项目目录结构图,很直观:

┌─uniCloud              云空间目录,阿里云为uniCloud-aliyun,腾讯云为uniCloud-tcb(详见uniCloud)
│─components            符合vue组件规范的uni-app组件目录
│  └─comp-a.vue         可复用的a组件
├─utssdk                存放uts文件
├─pages                 业务页面文件存放的目录
│  ├─index
│  │  └─index.vue       index页面
│  └─list
│     └─list.vue        list页面
├─static                存放应用引用的本地静态资源(如图片、视频等)的目录,注意: 静态资源只能存放于此
├─uni_modules           存放[uni_module](/uni_modules)。
├─platforms             存放各平台专用页面的目录
├─nativeplugins         App原生语言插件
├─nativeResources       App端原生资源目录
│  ├─android            Android原生资源目录
|  └─ios                iOS原生资源目录
├─hybrid                App端存放本地html文件的目录
├─wxcomponents          存放小程序组件的目录
├─unpackage             非工程代码,一般存放运行或发行的编译结果
├─AndroidManifest.xml   Android原生应用清单文件
├─Info.plist            iOS原生应用配置文件
├─main.js               Vue初始化入口文件
├─App.vue               应用配置,用来配置App全局样式以及监听 应用生命周期
├─manifest.json         配置应用名称、appid、logo、版本等打包信息
├─pages.json            配置页面路由、导航条、选项卡等页面类信息
└─uni.scss              这里是uni-app内置的常用样式变量
	

着重介绍如下几个目录/文件

pages 目录

该目录下存放作为页面存在的 vue/nvue 文件(nvue 是 uni 下的一种特殊格式文件,后续会介绍),一般是在 pages 目录下创建同名的目录和文件。
快捷创建页面:

image.png

在左侧目录树右击,然后选择创建页面

image.png

都填写好以后,点击创建,就可以愉快得编写页面代码了。

page.json 文件

pages 目录下创建完页面相关的文件后,最重要的一步就是到 pages.json 文件(官网介绍)中注册页面。

pages.json 文件用来对 uni-app 进行全局配置,决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。

它类似微信小程序中app.json页面管理部分。

uni_modules 目录

uni 体系下的插件存放目录,开发者可以前往插件市场导入项目。uni_modules官网介绍)是uni-app的插件模块化规范(HBuilderX 3.1.0+支持)。

同时,uni 也支持 npm。通过 npm 命令安装的依赖会存放在 node_modules 目录下,并会在项目根目录生成 package.json 文件。

manifest.json 文件

manifest.json 文件(官网介绍)是应用的配置文件,用于指定应用的名称、图标、权限等。HBuilderX 创建的工程此文件在根目录,CLI 创建的工程此文件在 src 目录。

main.js 文件

main.js官网介绍)是 uni-app 的入口文件,主要作用是初始化vue实例、定义全局组件、使用需要的插件如 vuex。

相当于 vue 项目的 main.js 文件。

App.vue 文件

App.vue官网介绍)是uni-app的主组件,所有页面都是在App.vue下进行切换的,是页面入口文件。但App.vue本身不是页面,这里不能编写视图元素,也就是没有<template>

这个文件的作用包括:调用应用生命周期函数、配置全局样式、配置全局的存储globalData

应用生命周期仅可在App.vue中监听,在页面监听无效。

跨平台开发

uniapp 对于 vue 技术栈的同学还是相当友好的,关于具体完整的开发细节,可以前往官网查看学习,这里我大致总结下我在实际开发后,觉得比较重要的一些注意点。

uniapp 的跨端原理

uni-app 分编译器运行时(runtime)。uni-app 能实现一套代码、多端运行,是通过这2部分配合完成的。

编译器将开发者的代码进行编译,编译的输出物由各个终端的runtime进行解析,每个平台(Web、Android App、iOS App、各家小程序)都有各自的runtime。

编译器

编译器的作用就是将开发者按 uni-app 规范编写的代码,编译生成每个平台支持的特有代码

  • 在web平台,将.vue文件编译为js代码。与普通的vue cli项目类似。
  • 在微信小程序平台,编译器将.vue文件拆分生成wxml、wxss、js等代码。
  • 在app平台,将.vue文件编译为js代码。并且,uni 是支持接入原生代码的。
  • 编译器支持条件编译,即可以指定某部分代码只编译到特定的终端平台。从而将公用和个性化融合在一个工程中。

条件编译

条件编译官网)是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。

这为我们在开发跨平台应用时,为各自平台编写个性化代码提供了便捷的方式。

不同于写大量的 if/else ,由于是在编译器层面进行的平台区分,可以规避非当前平台的冗余代码。

// #ifdef  App
console.log("这段代码只有在App平台才会被编译进去。非App平台编译后没有这段代码")
// #endif

运行时

runtime 不是运行在电脑开发环境,而是运行在真正的终端上。

uni-app 在每个平台(Web、Android App、iOS App、各家小程序)都有各自的 runtime。

  • 在小程序端,uni-app 的 runtime,主要是一个小程序版的 vue runtime,页面路由、组件、api等方面基本都是转义。
  • 在 web 端,uni-app 的 runtime相比普通的vue项目,多了一套ui库、页面路由框架、和uni对象(即常见API封装)
  • 在 App 端,uni-app 的 runtime 更复杂,可以先简单理解为 DCloud 也有一套小程序引擎,打包app时将 开发者的代码DCloud的小程序 打包成了apk或ipa。

uni-app runtime包括3部分:基础框架组件API

基础框架

基础框架包括语法、数据驱动、全局文件、应用管理、页面管理、js引擎渲染和排版引擎

这里着重讲下 js 引擎和渲染引擎:

  • 在web和小程序上,不需要uni-app提供js引擎和排版引擎,直接使用浏览器和小程序的即可。
  • 但是在 app 端:
    • js 引擎:App-Android上,uni-app的js引擎是v8,App-iOS是jscore
    • 渲染引擎:.vue页面文件由webview渲染,原理与小程序相同;.nvue页面文件由原生渲染,原理与react native相同。两者的区别可以前往官网学习。(.nvue页面文件在 css 兼容性上有要求限制,但是可以提供更高的性能)

组件

runtime中包括的组件只有基础组件(官网),如<view><button>等。扩展组件不包含在uni-app的runtime中,而是下载到用户的项目代码中。(这些组件都是vue组件)

之前提到的 uni-ui 就是基于内置基础组件封装的 UI 库(官网)。

API

uni-app runtime内置了大量常见的、跨端的 API,比如联网(uni.request)、读取存储(uni.getStorage)

使用uni-app的标准API,可以跨端使用。但对于不跨端的部分,仍可以调用该端的专有API。由于常见的API都已经被封装内置,所以日常开发时,开发者只需关注uni标准API,当需要调用特色端能力时在条件编译里编写特色API调用代码。

当所有这些 API 都无法满足需求时,可以通过 ext API 来接入自定义 API 。

注意:
因为 uniapp 在非 h5 平台出于性能考虑,是进行了逻辑层(js)和渲染层(html、css)的分离。

不管小程序还是app,逻辑层都独立为了单独的js引擎,渲染层仍然是webview(app上也支持纯原生渲染nvue)。

所以注意小程序和app的逻辑层都不支持浏览器专用的window、dom等API。app只能在渲染层操作window、dom,即renderjs。(renderjs只支持app。开发项目中上传、下载由于需要操作数据流,在 app 端如果直接使用 api 是无法实现需求的,所以我的方案就是借用了 renderjs 的能力,使用了和 h5 端一样的方案:new XMLHttpRequest()

结语

总的来说,uni-app 提供的跨平台方案还是一个很不错的解决方案。

因为既然选择了跨平台,说明公司/开发者是不愿意承担多套原生代码的开发、维护成本的。鱼和熊掌不可兼得,跨平台带来的兼容性问题(坑)、性能问题,是不可避免的。但是得益于 uniapp 庞大的社区和专业的官方团队,绝大多数的问题都能得到解决。再不济,uni 还是可以桥接原生代码的。👏

除了 uni,本人其实也有 flutter 的开发经验。之前用 flutter 做过一个直播类型的软件,主要是从服务端拉取 rtsp 流,进行解码播放。

如果只是单纯做app 跨端(Android 和 iOS),flutter 其实也是一个不错的选择。dart 作为一个编译型强类型语言,加之 flutter 独有的原生渲染引擎,使得 flutter 已经具有了无限接近原生的性能体验。

但是,国内因为小程序的火爆,注定 flutter 无法大范围铺开,而且 uni 几乎适配了市面上所有的小程序端。得益于 nvue 模式的存在,在一些需要高性能的页面,开发者大可以牺牲一点开发的便利,选择 nvue 模式。

至于 RN,因为技术栈、工期压力等多方面原因,并没有去深入了解,欢迎 jym 补充、交流。🎉

所以,如果你的项目需要涵盖包含小程序在内的多个终端,而且无法承担多套原生代码的成本,那就无脑上 uniapp 吧。

下一篇文章,将会更新一些 uniapp 的开发经验,包括小技巧、踩坑。
欢迎点赞、收藏、订阅专栏。🎉 🎉 🎉