Uni-App小程序开发笔记

2024/7/29

# 微信小程序开发环境

# 微信小程序工具下载

下载 (opens new window)

# 小程序代码构成

.json 后缀的 JSON 配置文件 .wxml 后缀的 WXML 模板文件 .wxss 后缀的 WXSS 样式文件 .js 后缀的 JS 脚本逻辑文件

# JSON 配置

主要的 json 配置为 app.json, project.config.json 和每个页面下的 json 文件

# 小程序配置 app.json

app.json  是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。

{
  "pages": ["pages/index/index", "pages/logs/logs"],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "Weixin",
    "navigationBarTextStyle": "black"
  }
}
1
2
3
4
5
6
7
8
9
  1. pages 字段 —— 用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录。
  2. window 字段 —— 定义小程序所有页面的顶部背景颜色,文字颜色定义等。

其他配置可参考小程序文档

# 工具配置 project.config.json

通常大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如界面颜色、编译配置等等,当你换了另外一台电脑重新安装工具的时候,你还要重新配置。

考虑到这点,小程序开发者工具在每个项目的根目录都会生成一个project.config.json,你在工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。

# 页面配置 page.json

这里的  page.json  其实用来表示 pages/logs 目录下的  logs.json  这类和小程序页面相关的配置。开发者可以独立定义每个页面的一些属性。

# WXML 模板

类似于 html,用来描述页面结构的文件,和  HTML  非常相似,WXML  由标签、属性等等构成。但是也有很多不一样的地方。例如标签的名称,能使用 wx:if, wx:for 等属性和{{}}的表达式,具体参考https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/。如<text></text>

Js 文件通过这种方式渲染变量

this.setData({ msg: "Hello World" })

# WXSS 样式

WXSS  具有  CSS  大部分的特性,小程序在  WXSS  也做了一些扩充和修改。

  1. 新增了尺寸单位。在写  CSS  样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。WXSS  在底层支持新的尺寸单位  rpx ,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差。
  2. 提供了全局的样式和局部样式。和前边  app.json, page.json  的概念相同,你可以写一个  app.wxss  作为全局样式,会作用于当前小程序的所有页面,局部页面样式  page.wxss  仅对当前页面生效。
  3. 此外  WXSS  仅支持部分  CSS  选择器

更详细的文档可以参考  WXSS (opens new window) 。

JS 逻辑交互

负责用户交互,响应用户的点击、获取用户的位置等等。此外你还可以在 JS 中调用小程序提供的丰富的 API,利用这些 API 可以很方便的调起微信提供的能力,例如获取用户信息、本地存储、微信支付等。

# 宿主环境

# 渲染层和逻辑层

小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。

小程序的渲染层和逻辑层分别由 2 个线程管理:渲染层的界面使用了 WebView 进行渲染;逻辑层采用 JsCore 线程运行 JS 脚本。一个小程序存在多个界面,所以渲染层存在多个 WebView 线程,这两个线程的通信会经由微信客户端(图中 Native 代指微信客户端)做中转,逻辑层发送网络请求也经由 Native 转发,小程序的通信模型下图所示。

通信模型

# 程序与页面

微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地。

紧接着通过  app.json  的  pages  字段就可以知道你当前小程序的所有页面路径:

{
  "pages": ["pages/index/index", "pages/logs/logs"]
}
1
2
3

写在  pages  字段的第一个页面就是这个小程序的首页(打开小程序看到的第一个页面)。

于是微信客户端就把首页的代码装载进来,通过小程序底层的一些机制,就可以渲染出这个首页。

小程序启动之后,在  app.js  定义的  App  实例的  onLaunch  回调会被执行:

App({
  onLaunch: function () {
  // 小程序启动之后 触发
  }
})
1
2
3
4
5

整个小程序只有一个 App 实例,是全部页面共享的。

页面的实现是这样的,以 pages/logs/logs 为例,微信客户端会先根据  logs.json  配置生成一个界面,顶部的颜色和文字你都可以在这个  json  文件里边定义好。紧接着客户端就会装载这个页面的  WXML  结构和  WXSS  样式。最后客户端会装载  logs.js,你可以看到  logs.js  的大体内容就是:

Page({
  data: { // 参与页面渲染的数据
  logs: []
  },
  onLoad: function () {
  // 页面渲染后 执行
  }
})
1
2
3
4
5
6
7
8

Page  是一个页面构造器,这个构造器就生成了一个页面。在生成页面的时候,小程序框架会把  data  数据和  index.wxml  一起渲染出最终的结构,于是就得到了你看到的小程序的样子。

在渲染完界面之后,页面实例就会收到一个  onLoad  的回调,你可以在这个回调处理你的逻辑。

# 组件

和 HTML 的 div,p 标签一样,在小程序里边,你只需要在  WXML  写上对应的组件标签名字就可以把该组件显示在界面上,组件的内部行为也会通过事件的形式让开发者可以感知,当然你也可以通过  style  或者  class  来控制组件的外层样式,以便适应你的界面宽度高度等等。

# API

为了让开发者可以很方便的调起微信提供的能力,例如获取用户信息、微信支付等等,小程序提供了很多 API 给开发者去使用。

需要注意的是:多数 API 的回调都是异步,你需要处理好代码逻辑的异步问题。

# 架构

# 逻辑层

小程序开发框架的逻辑层使用  JavaScript  引擎为小程序提供开发  JavaScript  代码的运行环境以及微信小程序的特有功能。开发者写的所有代码最终将会打包成一份  JavaScript  文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似  ServiceWorker,所以逻辑层也称之为 App Service。小程序框架的逻辑层并非运行在浏览器中,因此  JavaScript  在 web 中一些能力都无法使用,如  window,document  等。

# 小程序注册

// app.js
App({
  onLaunch(options) {
    // Do something initial when launch.
  },
  onShow(options) {
    // Do something when show.
  },
  onHide() {
    // Do something when hide.
  },
  onError(msg) {
    console.log(msg);
  },
  globalData: "I am global data",
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过  getApp  方法获取到全局唯一的 App 实例,获取 App 上的数据或调用开发者注册在  App  上的函数。

// xxx.js
const appInstance = getApp();
console.log(appInstance.globalData); // I am global data
1
2
3

# 页面注册

//index.js
Page({
  data: {
    text: "This is page data.",
  },
  onLoad: function (options) {
    // 页面创建时执行
  },
  onShow: function () {
    // 页面出现在前台时执行
  },
  onReady: function () {
    // 页面首次渲染完毕时执行
  },
  onHide: function () {
    // 页面从前台变为后台时执行
  },
  onUnload: function () {
    // 页面销毁时执行
  },
  onPullDownRefresh: function () {
    // 触发下拉刷新时执行
  },
  onReachBottom: function () {
    // 页面触底时执行
  },
  onShareAppMessage: function () {
    // 页面被用户分享时执行
  },
  onPageScroll: function () {
    // 页面滚动时执行
  },
  onResize: function () {
    // 页面尺寸变化时执行
  },
  onTabItemTap(item) {
    // tab 点击时执行
    console.log(item.index);
    console.log(item.pagePath);
    console.log(item.text);
  },
  // 事件响应函数
  viewTap: function () {
    this.setData(
      {
        text: "Set some data for updating view.",
      },
      function () {
        // this is setData callback
      }
    );
  },
  // 自由数据
  customData: {
    hi: "MINA",
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 生命周期

# 模块化

类似 java 中的工具类,将一些公共代码抽成单独的 js 文件

// common.js
function sayHello(name) {
  console.log(`Hello ${name} !`);
}
function sayGoodbye(name) {
  console.log(`Goodbye ${name} !`);
}

module.exports.sayHello = sayHello;
exports.sayGoodbye = sayGoodbye;

// 使用
var common = require("common.js");
Page({
  helloMINA: function () {
    common.sayHello("MINA");
  },
  goodbyeMINA: function () {
    common.sayGoodbye("MINA");
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

小程序不支持引入 node_module,不过小程序支持 npm,跟一般前端开发使用的 npm 方式有略微不同。

# 视图层

框架的视图层由 WXML 与 WXSS 编写,由组件来进行展示。

将逻辑层的数据反映成视图,同时将视图层的事件发送给逻辑层。

# WXML

wxml (opens new window)

# WXSS

https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxss.html

wxss 相比 css 主要是在尺寸单位和样式导入上。

# 事件

事件是视图层到逻辑层的通讯方式。

# 绑定方式:

组件中的属性 bind***,参数携带 data-xxx

Click me!

Page({
  tapName: function(event) {
    console.log(event)
  }
})
1
2
3
4
5
# 事件类型

https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html

# uni-app 介绍

uni-app  是一个使用  Vue.js  开发所有前端应用的框架,开发者编写一套代码,可发布到 iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。

所以说,可以通过 uni-app,使用 vue.js 来开发小程序。使用 HBuilder 进行 uni-app 的开发,当编写好代码后,点击小程序运行,程序会自动打开微信开发者工具并进行编译,之后就可以在微信开发者工具中进行调试。

除了能一套代码多端运行之外,uni-app 还提供和微信小程序云开发一样的 uniCloud 的服务。微信小程序在 2022 年已经停止了开发版的云开发,现在要使用微信小程序的云开发至少得需要 19.9 的费用。同微信小程序的云开发相比,uniCloud 除了腾讯云之外还能使用阿里云的开发版云服务空间,这个服务空间是免费的,能很好的满足开发需求。

# uni-app 使用

下载开发 uni-app 配套的工具 HbuilderX: https://www.dcloud.io/hbuilderx.html

打开 HbuiderX,新建项目,选择 uni-app 类型,输入工程名,选择模版,点击创建。

# 项目结构

一个 uni-app 工程,默认包含如下目录及文件:

┌─uniCloud 云空间目录,支付宝小程序云为 uniCloud-alipay,阿里云为 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 详见 ├─platforms 存放各平台专用页面的目录,详见 ├─nativeplugins App 原生语言插件 详见 ├─nativeResources App 端原生资源目录 │ ├─android Android 原生资源目录 详见 | └─ios iOS 原生资源目录 详见 ├─hybrid App 端存放本地 html 文件的目录,详见 ├─wxcomponents 存放小程序组件的目录,详见 ├─unpackage 非工程代码,一般存放运行或发行的编译结果 ├─main.js Vue 初始化入口文件 ├─App.vue 应用配置,用来配置 App 全局样式以及监听 应用生命周期 ├─pages.json 配置页面路由、导航条、选项卡等页面类信息,详见 ├─manifest.json 配置应用名称、appid、logo、版本等打包信息,详见 ├─AndroidManifest.xml Android 原生应用清单文件 详见 ├─Info.plist iOS 原生应用配置文件 详见 └─uni.scss 内置的常用样式变量

重点是 pages 文件夹里,每一个.vue 文件就是一个页面,换言之现在是用 vue 语法写小程序页面。

# uni-app 和小程序开发上的不同

uni-app 中一个页面由一个.vue 文件构成,微信小程序中一个页面由 wxml,xwss 和 js 文件构成,.vue 文件中有三个一级节点,template,script,style,分别对应了 wxml,wxss,js。语法选用 vue 语法,控件使用小程序控件和 uni-app 自己的控件 ui,API 也是使用 uni-app 自己的 api,同时也兼容小程序的 api,其他方面并无本质上的区别。

# 在 uni-app 上运行微信小程序

进入项目,点击工具栏的运行 -> 运行到小程序模拟器 -> 微信开发者工具,即可在微信开发者工具里面体验 uni-app,也可如图所示运行:

这样系统会自动打开微信小程序并且运行 uni-app 代码。(注意,通过 uni-app 运行小程序需要开放微信开发者工具的端口访问)

# uni-app 云服务

# 创建服务空间

打开这个网址https://unicloud.dcloud.net.cn/, 创建服务空间(需要 DCloud 账号,并且要实名认证)。服务空间类型选择阿里云(也可以选择支付宝云,DCloud 提供阿里云和支付宝云的免费版),选择免费版点击创建,等待几分钟等待服务空间初始化即可。

# 创建项目

打开 HBuilderX,点击创建项目,选择创建 uni-app 项目,里面有个选项为启用 uniCloud,点击启用并选择阿里云。

创建好项目后需要关联服务空间,右键 uniCloud 文件夹,选择云服务空间或项目,选择新创建的服务空间即可。

# 云服务的简单使用(详细可看这个文档https://doc.dcloud.net.cn/uniCloud/)

云对象能够直接导入到前端进行使用,可以在云对象中编写函数,云对象在 cloudfunctions 目录下创建,目录结构如图:

图中的云对象名称为 co1,逻辑写在 index.obj.js 中,代码如下:

module.exports = {
  _before: function () {
    // 通用预处理器
  },
  say(text) {
    console.log("console: " + text);
    return {
      status_code: 0,
      data: "hello uniCloud",
    };
  },
};
1
2
3
4
5
6
7
8
9
10
11
12

通过 uniCloud.importObject("对象名")调用,云对象里的方法都为异步方法,代码如下:

async callco1(){
  const co1 = uniCloud.importObject("co1")
  let res = await co1.say("这是客户端传递到云服务器的参数")
  console.log(res)
}
1
2
3
4
5

同样前端也可以直接调用云数据库中的数据,代码如下:

callDB(){
  const db = uniCloud.database();
  db.collection("test1").get().then(res => {
    console.log(res)
    this.data = res.result.data
  }).catch(err => {
    console.log(err)
  })
}
1
2
3
4
5
6
7
8
9

# 命令行创建 uni-app 项目并用 VSCode 开发

npx degit dcloudio/uni-preset-vue#vite-ts 项目名称

通过上述命令能够创建一个 vue3+ts 版的 uni-app 项目,然后通过 vscode 打开项目,进入命令行终端,输入  pnpm i 下载依赖。依赖下载完成后,接下来就要在微信小程序中跑起来,我们使用 pnpm dev:mp-weixin 就能进行代码编译,编译完成后会多出来一个 dist 目录,里面就是微信小程序的代码,通过微信小程序开发者工具打开 dist 目录里面的 mp-weixin 文件,即可运行代码。同时如果你在 vscode 中修改了代码,开发者工具中也会同步进行实时的更新。

# 基于 Vue3+TS+uni-app 的小程序开发

# 创建 uni-app(vue3+ts 模版)项目

vue3+ts 版: npx degit dcloudio/uni-preset-vue#vite-ts

通过上述命令可以下载到 vue3+ts+uni-app 的模版文件,使用 vscode 打开项目,输入命令 pnpm install 下载依赖。依赖下载完成后,接下来就要在微信小程序中跑起来,我们使用 pnpm dev:mp-weixin 就能进行代码编译,编译完成后会多出来一个 dist 目录,里面就是微信小程序的代码,通过微信小程序开发者工具打开 dist 目录里面的 mp-weixin 文件,即可运行代码。同时如果你在 vscode 中修改了代码,开发者工具中也会同步进行实时的更新。

# vscode 工具的配置

# 安装 uni-app 插件

# 快速创建页面

下载上图插件,即可快速创建页面,创建方式如下, 在文件夹上右键多出了一个新建 uniapp 页面的选项,输入名称就会自动创建一个页面需要的文件, 同时 pages.json 中也会注册相应的信息。

# uni-helper

uni 相关的代码提示

# uniapp 小程序扩展

鼠标悬停能够直接查看相应控件的文档

# TS 类型校验

# 安装类型声明文件

pnpm i -D miniprogram-api-typings @uni-helper/uni-app-types

配置 tsconfig.json,在 types 中添加这两个包,并添加 vue 编译器的配置。

"compilerOptions": {
  ......
  "types": [
    "@dcloudio/types",
    "miniprogram-api-typings", //添加的包
    "@uni-helper/uni-app-types", //添加的包
  ]
},
"vueCompilerOptions": {
  // experimentalRuntimeMode 已废弃,现调整为 nativeTags,请升级 Volar 插件至最新版本
  "nativeTags": ["block", "component", "template", "slot"]
},
1
2
3
4
5
6
7
8
9
10
11
12

项目中有一些 json 文件会有注释,配置 vscode 使相关 json 文件支持注释

在 vscode 中打开设置,如下图所示设置

# 导入 uni-ui 组件库

# 安装 uni-ui

pnpm i @dcloudio/uni-ui

在 pages.json 中配置 easycom

// 组件自动引入规则
"easycom": {
  // 是否开启自动扫描
  "autoscan": true,
  "custom": {
    // uni-ui 规则如下配置
    "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
  }
},
1
2
3
4
5
6
7
8
9

配置 uni-ui 的类型校验,安装依赖 pnpm i -D @uni-helper/uni-ui-types

在 tsconfig.json 中配置

"types": [
  "@dcloudio/types",
  "miniprogram-api-typings",
  "@uni-helper/uni-app-types",
  "@uni-helper/uni-ui-types" //添加的包
]
1
2
3
4
5
6

# Pinia 持久化

创建 pinia 实例并导出给 main.ts 使用

import { createPinia } from "pinia";
import persist from "pinia-plugin-persistedstate";

// 创建 pinia 实例
const pinia = createPinia();
// 使用持久化存储插件
pinia.use(persist);

// 默认导出,给 main.ts 使用
export default pinia;

// 模块统一导出
export * from "./modules/member";
1
2
3
4
5
6
7
8
9
10
11
12
13

在 mian.ts 中加上 app.use(pinia)

定义 store 的代码如下:

import { defineStore } from 'pinia'
import { ref } from 'vue'

// 定义 Store
export const useMemberStore = defineStore(
'member',
() => {
  // 会员信息
  const profile = ref<any>()

    // 保存会员信息,登录时使用
    const setProfile = (val: any) => {
      profile.value = val
    }

    // 清理会员信息,退出时使用
    const clearProfile = () => {
      profile.value = undefined
    }

    // 记得 return
    return {
      profile,
      setProfile,
      clearProfile,
    }
},
// TODO: 持久化
{
  persist: {
    storage: {
      getItem(key) {
        return uni.getStorageSync(key)
      },
      setItem(key, value) {
        uni.setStorageSync(key, value)
      },
    }
  }
},
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 请求工具封装

# 请求拦截器

/**
 * 1.  非 http 开头需拼接地址
 * 2.  请求超时
 * 3.  添加小程序端请求头标识
 * 4.  添加 token 请求头标识
 */

import { useMemberStore } from "@/stores";

const baseURL = "https://pcapi-xiaotuxian-front-devtest.itheima.net";

const httpInterceptor = {
  invoke(options: UniApp.RequestOptions) {
    // 1. 非 http 开头需拼接地址
    console.log(options.url);
    if (!options.url.startsWith("http")) {
      var new_url: string = options.url.startsWith("/") ? options.url : "/" + options.url;
      options.url = baseURL + new_url;
    }
    // 2. 请求超时
    options.timeout = 10000;
    // 3. 添加小程序端请求头标识
    options.header = {
      ...options.header,
      "source-client": "miniapp",
    };
    // 4. 添加 token 请求头标识
    const memberStore = useMemberStore();
    const token = memberStore.profile?.token;
    if (token) {
      options.header.Authorization = token;
    }
    console.log(options);
  },
};
uni.addInterceptor("request", httpInterceptor);
uni.addInterceptor("uploadFile", httpInterceptor);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 请求函数封装

/**
* 请求函数
* @param UniApp.RequestOptions
* @returns Promise
* 1. 返回 Promise 对象
* 2. 获取数据成功
* 2.1 提取核心数据 res.data
* 2.2 添加类型,支持泛型
* 3. 获取数据失败
* 3.1 401 错误 -> 清理用户信息,跳转到登录页
* 3.2 其他错误 -> 根据后端错误信息轻提示
* 3.3 网络错误 -> 提示用户换网络
*/

type Data<T> = {
  code: string
  msg: string
  result: T
}
// 2.2 添加类型,支持泛型
export const http = <T>(options: UniApp.RequestOptions) => {
  // 1. 返回 Promise 对象
  return new Promise<Data<T>>((resolve, reject) => {
    uni.request({
      ...options,
      // 响应成功
      success(res) {
        // 状态码 2xx, axios 就是这样设计的
        if (res.statusCode >= 200 && res.statusCode < 300) {
          // 2.1 提取核心数据 res.data
          resolve(res.data as Data<T>)
        } else if (res.statusCode === 401) {
          // 401 错误 -> 清理用户信息,跳转到登录页
          const memberStore = useMemberStore()
          memberStore.clearProfile()
          uni.navigateTo({ url: '/pages/login/login' })
          reject(res)
        } else {
          // 其他错误 -> 根据后端错误信息轻提示
          uni.showToast({
            icon: 'none',
            title: (res.data as Data<T>).msg || '请求错误',
          })
          reject(res)
        }
      },
      // 响应失败
      fail(err) {
        uni.showToast({
          icon: 'none',
          title: '网络错误,换个网络试试',
        })
        reject(err)
      },
    })
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 隐藏默认导航栏

在 pages.json 文件的页面样式中添加"navigationStyle": "custom",即可隐藏导航栏。

# typescript 和相关用法

?.: 可选链操作符,允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。

const obj = {
  name: "ceshi",
  detail: {
    cat: "huahua",
  },
};
const name = obj.dog?.name;
console.log(name); // undefined

const detail = obj.detail?.cat;
console.log(detail); //huahua
1
2
3
4
5
6
7
8
9
10
11

key!:非空断言, 它用来告诉编译器该变量的值不会为 null。

例如,假设有一个函数  foo  返回一个字符串类型,它不会返回 null:

tsfunction foo(): string {
  return 'hello';
}

const myString: string = foo()!;
1
2
3
4
5

在这个例子中,!  表示断言该值不会是 null,因此编译器不会检查  foo()  是否为 null,而会将其视为非空字符串。

# 全局组件导入

在 components 文件夹下写自定义组件可以在 pages.json 中的 easycom 中进行配置,

"easycom": {
  // 是否开启自动扫描
  "autoscan": true,
  // 以正则方式自定义组件匹配规则
  "custom": {
  // uni-ui 规则如下配置
  "^uni-(._)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
  // 以 Xtx 开头的组件,在 components 文件夹中查找引入(需要重启服务器)
  "^Xtx(._)": "@/components/Xtx$1.vue"
  }
},
1
2
3
4
5
6
7
8
9
10
11

并在 types 文件夹下创建一个.d.ts 文件做组件类型定义。

import XtxSwiper from "@/components/XtxSwiper.vue";
import XtxGuess from "@/components/XtxGuess.vue";

declare module "vue" {
  export interface GlobalComponents {
    XtxSwiper: typeof XtxSwiper;
    XtxGuess: typeof XtxGuess;
  }
}

// 组件实例类型
export type XtxGuessInstance = InstanceType<typeof XtxGuess>;
export type XtxSwiperInstance = InstanceType<typeof XtxSwiper>;
1
2
3
4
5
6
7
8
9
10
11
12
13

# Uni-app+ts 中事件的类型

通过 UniHelper.xxxx 能得到 uni-app 中大多数事件的类型

// 当 swiper 下标发生变化时触发
const onChange: UniHelper.SwiperOnChange = (ev) => {
  activeIndex.value = ev.detail.current;
};
1
2
3
4
上次更新: 7/29/2024