uni-app 简介
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到 iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
uni-app x 简介
uni-app x,是下一代 uni-app,是一个跨平台应用开发引擎。
uni-app x 是一个庞大的工程,它包括 uts 语言、uvue 渲染引擎、uni 的组件和 API、以及扩展机制。
uts 是一门类 ts 的、跨平台的、新语言。
uts 在 iOS 平台编译为 swift、在 Android 平台编译为 kotlin、在 Web 和小程序平台编译为 js、在鸿蒙 next 平台上编译为 ArkTS。
在 Android 平台,uni-app x 的工程被整体编译为 kotlin 代码,本质上是换了 vue 写法的原生 kotlin 应用,在性能上与原生 kotlin 一致。
uts 语言
开发者在 uni-app x 中,需使用 uts 而不是 js。尤其是 Android 端不自带 js 引擎,无法运行 js 代码。
uts 全称 uni type script,是一门跨平台的、高性能的、强类型的现代编程语言。它在不同平台,会被编译为不同平台的 native 语言,如:
- web/小程序平台,编译为 JavaScript
- Android 平台,编译为 Kotlin
- iOS 平台,编译 Swift
- 鸿蒙 next 平台,编译为 arkts
uts 采用了与 ts 基本一致的语法规范,支持绝大部分 ES6 API。
但为了跨端,uts 进行了一些约束和特定平台的增补。过去在 js 引擎下运行支持的语法,大部分在 uts 的处理下也可以平滑的在 kotlin 和 swift 中使用。但有一些无法抹平,需要使用条件编译。
和 uni-app 的条件编译类似,uts 也支持条件编译。写在条件编译里的,可以调用平台特有的扩展语法
uts 不支持 js 的一些功能和特性
- 不支持 undefined。任何变量被定义后,都需要赋值
- 函数声明方式不支持作为值传递
- 函数表达式方式不支持默认参数
- 不存在(变量、函数等)声明提升,需要先声明,后使用,不可以访问未声
- 所有 vue 公开的 API 都是不需要 import 的, uni-app x 会自动引入。明的变量或函数(包括自身
UTS 的类型有:
- 基础类型:boolean、number、string、any、null,都是小写。前 3 个 typeof 返回类型名称,null 的 typeof 是 object,any 的 typeof 是运行时值的类型。
- 对象类型:Date、Array、Map、Set、UTSJSONObject,首字母大写。typeof 返回"object",判断准确类型需使用 instanceof
- 使用 type 来自定义类型
- 特殊类型:function、class、error。
- 平台专有类型:BigInt、Int、Float、Double、NSString、kotlin.Array...
除了特殊类型,其他类型都可以在变量后面通过:加类型名称来给这个变量声明类型。
uvue 渲染引擎
uts 替代的是 js,而 uvue 替代的就是 html 和 css。或者如果你了解 flutter 的话,也可以理解为 uts 类似 dart,而 uvue 类似 flutter。
uvue 是一套基于 uts 的、兼容 vue 语法的、跨平台的、原生渲染引擎。uvue 支持的是 vue3 语法,支持组合式 API 和选项式 API。
- Android 版于 3.99 上线
- Web 版于 4.0 上线
- iOS 版于 4.11 上线
- uvue 渲染引擎包括 uts 版的 vue 框架(组件、数据绑定...)、跨平台基础 ui、css 引擎。
有了 uvue,开发者就可以使用 vue 语法、css 来快速编写页面,编译为不同平台的、高性能的纯原生界面。页面与组件均符合vue的单文件组件规范,只不过页面需要在pages.json中注册且多了一批生命周期和API。
<template>
<view class="content">
<button @click="buttonClick">{{ title }}</button>
</view>
</template>
<script setup>
//lang 仅支持uts,不管script的lang属性写成什么,都按uts编译。
//注意在iOS的js引擎驱动的uvue页面里,uts会被编译为js。
// setup 组合式写法,如果没有setup属性则为选项式写法
let title = ref("Hello world");
const buttonClick = () => {
console.log("按钮被点了");
};
//获取当前页面实例
let instance = getCurrentPages();
//获取当前uniapp实例
let app = getApp();
onReady(() => {
console.log("页面onReady触发页面生命周期,编写页面加载后的逻辑");
});
</script>
<script>
//可以直接调用 Android 和 iOS 的 api
import Build from 'android.os.Build';
import { state, setLifeCycleNum } from '@/store/index.uts'
let firstBackTime = 0
export default {
data() {
const date = new Date() //自动推导类型为Date
const v = 1; //自动推导为number
return {
buttonEnable: false, //自动推导为boolean
s1 : "hello", // 根据字面量推导为string
n1 : 0 as number, // 这里其实可以根据字面量自动推导,as number写不写都行
n2, // 不合法,必须指定类型。真实运行时请删掉本行
n3 as number, // 不合法,uts不支持undefined,必须初始化。真实运行时请删掉本行
n4 : null as number | null // 合法。定义为可为null的数字,初始值是null,但在使用n4前必须为其赋值数字
year: date.getFullYear() as number, // 在data里,目前无法通过变量类型推导data项的类型,需使用 as 显式声明
t: ``, // 模板字面量,推导为 string
o: { id: 1, name:"DCloud" }, // 对象字面量,推导为 UTSJSONObject,注意:访问 data 中定义的UTSJSONObject属性时,需要使用索引访问,如 this.o["id"]
an: [1, 2], // 数组字面量,如果元素均为纯数字字面量,则推导为 Array<number>
as: ['1', '2', `3`], // 数组字面量,如果元素均为纯字符串或模板字符串字面量,则推导为 Array<string>
ab: [true, false], // 数组字面量,如果元素均为boolean字面量,则推导为 Array<boolean>
ao: [{ id: 1 }, { id: 2 }], // 数组字面量,如果元素均为对象字面量,则推导为 Array<UTSJSONObject>
am: [[1, 2], [2, 3], [3, 4]], // 数组字面量,支持嵌套推导,推导为 Array<Array<number>>
aa: [1, '2'], // 数组字面量,如果元素类型不一致,则推导为 Array<any|null>
u: { name: 'DCloud' } as User, // 类型断言,如果主动指定了类型,则不做自动推导,使用指定的类型,注意:自定义type,需要定义在 export default 外部或通过其他文件导入
au: [{ name: 'DCloud' }] as User[], // 类型断言,支持数组类型断言
v: v, // 非字面量类型,目前未指定类型断言,推导为 any | null,建议此情况,均通过as手动指定类型
},
},
methods: {
buttonClick () {
uni.showModal({
"showCancel": false,
"content": "点了按钮"
})
// 发起跳转,并传入post_id参数
uni.navigateTo({
url: '/pages/template/list-news/detail/detail?post_id=' + post_id
})
},
increasetLifeCycleNum() {
setLifeCycleNum(state.lifeCycleNum + 100)
}
},
//声明周期函数: 类型非必填,可自动推导
onLoad(event : OnLoadOptions) {
this.post_id = event["post_id"] ?? "";
//调用原生对象,返回手机型号
console.log(Build.MODEL);
//调用uni API,返回手机型号。与上一行返回值相同
console.log(uni.getSystemInfoSync().deviceModel);
},
onLaunch () {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 1000)
console.log('App Launch')
// 页面性能分析
const performance = uni.getPerformance()
const observer1: PerformanceObserver = performance.createObserver(
(entryList: PerformanceObserverEntryList) => {
console.log('observer1:entryList.getEntries()' +JSON.stringify(entryList.getEntries()))
}
)
observer1.observe({
entryTypes: ['render', 'navigation'],
} as PerformanceObserverOptions)
},
onShow () {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 100)
console.log('App Show')
},
onHide () {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum - 100)
console.log('App Hide')
},
onLastPageBackPress () {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum - 1000)
console.log('App LastPageBackPress')
if (firstBackTime == 0) {
uni.showToast({
title: '再按一次退出应用',
position: 'bottom',
})
firstBackTime = Date.now()
setTimeout(() => {
firstBackTime = 0
}, 2000)
} else if (Date.now() - firstBackTime < 2000) {
firstBackTime = Date.now()
uni.exit()
}
},
onReady() {
console.log('页面加载完成')
},
onExit() {
console.log('App Exit')
},
onReachBottom() {
console.log('可在pages.json里定义具体页面底部的触发距离onReachBottomDistance, 比如设为50,那么滚动页面到距离底部50px时,就会触发onReachBottom事件')
},
onPageScroll({scrollTo:number}) {
console.log('App 页面在垂直方向已滚动的距离(单位 px)')
},
onResize({deviceOrientation,size}) {
console.log('App Exit')
},
onBackPress() {
console.log('- backbutton 顶部导航栏左边的返回按钮或 Android 实体返回键 navigateBack 返回 API,即 uni.navigateBack()')
},
onTabItemTap({index,pagePath,text}) {
console.log('点击tabItem')
},
onNavigationBarButtonTap({index}) {
console.log('点击导航栏按钮')
},
onNavigationBarSearchInputChanged() {
console.log('导航栏搜索框内容变化')
},
onNavigationBarSearchInputConfirmed() {
console.log('导航栏搜索框内容确认')
},
}
</script>
//style的写法与web的css基本相同。但在App端,由于并非webview渲染,支持的css有限.
//一个页面/组件允许有多个style标签。style通过lang属性,可以支持less、scss、stylus等css预处理语言
<style>
@import "./common/uni.css";
.content {
width: 750rpx;
background-color: white;
}
</style>
项目结构
┌─uniCloud 云空间目录,支付宝小程序云为uniCloud-alipay,阿里云为uniCloud-aliyun,腾讯云为uniCloud-tcb
│─components 符合vue组件规范的uni-app x组件目录
│ └─comp-a.vue 可复用的a组件
├─utssdk 存放uts文件
├─pages 业务页面文件存放的目录
│ ├─index
│ │ └─index.uvue index页面
│ └─list
│ └─list.uvue list页面
├─static 存放应用引用的本地静态资源(如图片、字体、音视频等)的目录,注意:静态资源都应存放于此目录
├─uni_modules 存放uni_module
├─platforms 存放各平台专用页面的目录
├─nativeResources App端原生资源目录
│ ├─android Android原生资源目录
| └─ios iOS原生资源目录
├─hybrid App端存放web-view组件使用的本地html文件的目录
├─wxcomponents 微信小程序平台wxml组件专用目录
├─unpackage 非工程代码,一般存放运行或发行的编译结果、App自定义基座。默认应配置git忽略
├─main.uts Vue初始化入口文件
├─App.uvue 应用配置,用来配置App全局样式以及监听 详见
├─pages.json 配置页面路由、导航条、选项卡等页面类信息
├─manifest.json 配置应用名称、appid、logo、版本等打包信息
├─AndroidManifest.xml Android原生应用清单文件
├─Info.plist iOS原生应用配置文件
└─uni.scss 内置的常用样式变量