Skip to content

uni-app 入门 ​

文档:https://uniapp.dcloud.io/quickstart?id=发布uni-app

一、快速上手 ​

下载开发工具 HBuilderX:https://www.dcloud.io/hbuilderx.html

1. 创建 uni-app ​

点击工具栏里的文件 -> 新建 -> 项目

  1. 输入工程名;2. 选择项目目录文件;3. 选择 uni-ui 模板;4. 选择 vue 的版本,点击创建

HBuilderX 新建 uni-app 项目对话框:填写工程名与项目目录,选择 uni-ui 模板和 Vue 版本

提示:在代码区输入字母 u,即可通过代码助手列出所有可用组件。光标置于组件名称处按 F1,即可查看组件文档

2. 运行 uni-app ​

(1)浏览器运行 ​

点击工具栏的运行 -> 运行到浏览器 -> 选择浏览器

(2)真机运行 ​

步骤一:开启 USB 调试

Android 版:在设置,系统,关于手机中找到版本号,连续点击五次,会进入开发者模式,然后回退一下,有个开发者选项,然后开启 USB 调试,(华为手机要关闭掉监控 ADB 安装应用选项:)

步骤二:进行授权

使用 USB 将手机插入电脑。如果设备出现调试授权提示,请授权你的电脑可以访问该设备。

HBuilderX 运行菜单展开「运行到手机或模拟器」,列出已连接的安卓真机

步骤三:运行程序

点击工具栏的运行 -> 真机运行 -> 选择运行的设备

(3)微信开发者工具里运行 ​

下载微信开发者工具:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

在微信开发者工具中,选择设置 -> 安全设置 -> 开启服务端口

提示:如果是第一次使用,还需配置微信开发者工具的安装目录。在运行到小程序模拟器 > 运行设置中配置

HBuilderX 小程序运行配置:指定微信开发者工具路径,也可点浏览选择安装目录

点击工具栏的运行 -> 运行到小程序模拟器 -> 微信开发者工具

HBuilderX 运行菜单:运行到小程序模拟器 -> 微信开发者工具

3. 安装常用插件 ​

插件市场:https://ext.dcloud.net.cn/?cat1=1&cat2=11

  1. Prettier:在格式化时可选择 Prettier

  2. eslint-plugin-vue

二、VSCode 改造 ​

如果使用 VSCode 开发习惯了,使用 HBuilderX 开发可能不太顺手。可使用 HBuilderX 运行程序,使用 VSCode 修改程序代码。使用 VSCode 开发 uni-app,需做一些额外配置。

1. TypeScript ​

使 TypeScript 能够识别 uni 相关 API;并且配置路径映射,配合别名使用

(1)安装 ​

bash
yarn add @types/node -D
yarn add @dcloudio/types -D
yarn add @dcloudio/uni-app -D
yarn add vue@3.2.6 @vue/runtime-dom@3.2.6 -D

vue 的版本是依据 D:\HBuilderX\plugins\hbuilderx-language-services\builtin-dts\node_modules\vue@3 目录下的 Vue 版本

(2)新建 tsconfig.json ​

json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "sourceMap": true,
    "skipLibCheck": true,
    "importHelpers": true,
    "allowSyntheticDefaultImports": true,
    "useDefineForClassFields": true,
    "resolveJsonModule": true,
    "lib": ["esnext", "dom"],
    "types": ["@dcloudio/types", "node"],
    "baseUrl": ".",
    "paths": { "@/*": ["./*"] }
  },
  "exclude": ["node_modules", "uni_modules", "unpackage", "src/**/*.nvue"]
}

2. ESlint、Prettier ​

(1)安装 ​

bash
//eslint 安装
yarn add eslint@^8.39.0 -D

//eslint vue插件安装
yarn add eslint-plugin-vue@^9.11.0 -D

//eslint 识别ts语法
yarn add @typescript-eslint/parser@^6.19.0 -D

//eslint ts默认规则补充
yarn add @typescript-eslint/eslint-plugin@^6.19.0 -D

//eslint prettier插件安装
yarn add eslint-plugin-prettier@^5.1.3 -D

//用来解决与eslint的冲突
yarn add eslint-config-prettier@^9.1.0 -D

//安装prettier
yarn add prettier@^3.2.4 -D

(2)新建 .eslintrc.cjs ​

js
module.exports = {
  globals: {
    uni: "readonly", // 声明 uni 为全局只读变量
  },
  parser: "vue-eslint-parser",
  extends: [
    "eslint:recommended", //继承 ESLint 内置的推荐规则
    "plugin:vue/vue3-recommended", // 继承 Vue.js 3 的推荐规则
    "plugin:@typescript-eslint/recommended", //继承 TypeScript ESLint 插件的推荐规则
    "plugin:prettier/recommended", //继承 Prettier 的推荐规则
    "eslint-config-prettier", //关闭 ESLint 中与 Prettier 冲突的规则
  ],
  parserOptions: {
    ecmaVersion: "latest",
    parser: "@typescript-eslint/parser",
    sourceType: "module",
    ecmaFeatures: {
      jsx: true,
    },
  },
  ignorePatterns: [
    "dist",
    "node_modules",
    ".eslintrc.cjs",
    "commitlint.config.cjs",
  ],
  plugins: ["vue", "@typescript-eslint", "prettier"],
  rules: {
    "vue/multi-word-component-names": "off", // 禁用vue文件强制多个单词命名
    "vue/require-default-prop": "off", //允许props没有默认值
    "@typescript-eslint/no-explicit-any": "off", //允许使用any
    "@typescript-eslint/no-this-alias": [
      "error",
      {
        allowedNames: ["that"], // this可用的局部变量名称
      },
    ],
    "@typescript-eslint/ban-ts-comment": "off", //允许使用@ts-ignore
    "@typescript-eslint/no-non-null-assertion": "off", //允许使用非空断言
    "no-console": [
      //提交时不允许有console.log
      "warn",
      {
        allow: ["warn", "error"],
      },
    ],
    "no-debugger": "warn", //提交时不允许有debugger
  },
};

(3)新建 .prettierrc ​

json
{
  "endOfLine": "auto",
  "printWidth": 120,
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "all",
  "bracketSpacing": true
}

(4)新建 .prettierignore ​

text
# 忽略格式化文件 (根据项目需要自行添加)

node_modules
dist

(5)重启 vscode 使配置生效 ​

(6)配置 package.json ​

json
"scripts": {
"lint": "eslint --fix --ext .js,.ts,.vue --report-unused-disable-directives --max-warnings 0"
},

运行 yarn run lint 修复一些 ESlint 能够自动修复的问题,例如双引号改为单引号

3. vue 语法提示 ​

在 VScode 中,要使用 Vue 语法提示,除了安装 Vue - Official 插件,还需配置 vite.config.js

(1)安装 ​

bash
yarn add @vitejs/plugin-vue -D

提示:不要配置 vite.config.js,否则 HBuilderX 默认配置会失效,导致启动报错

三、差异点 ​

1. 标签 ​

组件标签靠近小程序规范(div 使用 <view>,span 使用 <text>)

2. 接口 ​

接口能力靠近微信小程序规范,但需将前缀 wx 替换为 uni

3. 尺寸单位 ​

px、%、rpx

rpx 与微信小程序 rpx 效果相同。

举例说明:

若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设为:750 * 100 / 640,结果为:117rpx。

若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 375px,那么元素 B 在 uni-app 里面的宽度应该设为:750 * 375 / 375,结果为:750rpx。

若设计稿宽度为 750px,元素 B 在设计稿上的宽度为 750px,那么元素 B 在 uni-app 里面的宽度应该设为:750 * 750 / 750,结果为:750rpx。

4. 引用组件 ​

传统 vue 项目开发,引用组件需要导入 - 注册 - 使用三个步骤,如下:

vue
<template>
  <view>
    <!-- 3.使用组件 -->
    <uni-rate text="1"></uni-rate>
  </view>
</template>

<script>
// 1. 导入组件
import uniRate from "@/components/uni-rate/uni-rate.vue";
export default {
  components: { uniRate }, // 2. 注册组件
};
</script>

Vue 3.x 增加了 script setup 特性,将三步优化为两步,无需注册步骤,更为简洁

uni-app 的 easycom 机制,将组件引用进一步优化,开发者只管使用,无需考虑导入和注册(将组件定义在最外层的 components 下,能够直接在页面使用)

vue
<template>
  <view>
    <!-- 1.使用组件 -->
    <uni-rate text="1"></uni-rate>
  </view>
</template>

<script></script>

提示:对于静态文件使用绝对路径(从根目录开始),但 js 文件不支持绝对路径的方式引入,可使用相对路径,或路径别名 @(指向项目根目录)

5. 条件编译 ​

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

写法:以 #ifdef 或 #ifndef 加 %PLATFORM%,以 #endif 结尾

  • #ifdef:if defined 仅在某平台存在
  • #ifndef:if not defined 除了某平台均存在
  • %PLATFORM%:平台名称

条件编译写法示例:ifdef APP-PLUS 仅在 App 平台生效,ifndef H5 在除 H5 外各平台生效,ifdef H5 || MP-WEIXIN 在两个平台同时生效

%PLATFORM% 可取值(上):APP-PLUS、APP-PLUS-NVUE、H5、MP-WEIXIN、MP-ALIPAY、MP-BAIDU、MP-TOUTIAO

%PLATFORM% 可取值(下):MP-QQ、MP-360、MP、quickapp-webview 及快应用联盟与华为

在 HBuilderX 中,按 ctrl+alt+/ 即可生成正确注释。支持 API 条件编译,组件条件编译,样式条件编译,pages.json 条件编译

pages.json 条件编译示例:用 // #ifdef APP-PLUS 与 // #endif 包裹单个页面配置,仅 App 平台生效

static 目录的条件编译。static 目录下新建不同平台的专有目录(目录名称同 %PLATFORM%,但字母均为小写),专有目录下的静态资源只有在特定平台才会被编译进去。

如以下目录结构,a.png 只有在微信小程序平台才会编译进去,b.png 在所有平台都会被编译。

text
┌─static
│ ├─mp-weixin
│ │ └─a.png
│ └─b.png
├─main.js
├─App.vue
├─manifest.json
└─pages.json

整体目录条件编译。在 uni-app 项目根目录创建 platforms 目录,然后在下面进一步创建 app-plus、mp-weixin 等子目录,存放不同平台的文件

注意:platforms 目录下只支持放置页面文件(即页面 vue 文件),如果需要对其他资源条件编译建议使用 static 目录的条件编译

6. Tab 高度 ​

在布局的时候,有时候需要考虑底部 Tab 栏高度的占位

CSS:

css
var(--tab-bar-height)

JS:

js
uni.getSystemInfo({
  success: (res) => {
    const { screenHeight, windowHeight } = res;
    this.tabBarHeight = screenHeight - windowHeight; // 底部 TabBar 高度
  },
});

提示:对于整个页面的高度,在 H5 中时包含底部 Tab 高度的,因此会遮挡,需额外设置 padding-bottom。在微信小程序中,整个页面的高度是不包含底部 Tab 高度

四、全局配置 ​

1. 引入字体图标 ​

首先将图标加到购物车,然后选择 Font class 点击下载到本地,然后将 iconfont 开头的所有文件都复制到项目的 static 文件夹下新建的 icon 目录。在 App.vue 的 style 区域全局引入,或者在页面的 style 区域单独引入。

css
@import url("./static/icon/iconfont.css");

修改 iconfont.css 文件,增加路径 ~@/static/icon/...

iconfont.css 的 @font-face 片段:src 各项字体地址改为 ~@/static/icon/iconfont 前缀

之后就可以在页面中使用,<view class="iconfont icon-zhuti_tiaosepan_o"></view>

2. H5 跨域 ​

方案一:使用 HBuilderX 内置浏览器

HBuilderX 右上角点击「预览」运行到内置的 Web 浏览器标签页

方案二:使用 Chrome 代理插件

地址:https://chromewebstore.google.com/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf

安装完扩展后,选择开启

Allow CORS 扩展弹窗:点击左下角 Toggle ON|OFF 开启跨域

3. 小程序配置域名白名单 ​

在各个小程序平台运行时,网络相关的 API 在使用前需要配置域名白名单

以微信小程序为例,登录小程序后台 https://mp.weixin.qq.com/wxamp/devprofile/get_profile

在开发 -> 开发管理 -> 开发设置 -> 服务器域名中进行配置(request,socket,uploadFile 都需配置)

微信小程序后台「服务器域名」配置:分别填写 request、socket、uploadFile 合法域名

注意点:

  • 域名不能使用 IP 地址或 localhost,且不能带端口号
  • 域名必须经过 ICP 备案
  • 对于每个接口,分别可以配置最多 20 个域名

在本地开发中,选择小程序开发者工具 -> 详情 -> 本地设置 -> 打开不校验合法域名。等到上线时再打开去检查域名的合法性

4. 拦截器 ​

使用 uni.addInterceptor 可实现全局拦截功能

(1)请求拦截器 ​

新建 interceptors/request.ts

ts
const baseUrl = "";

// 拦截器配置
const httpInterceptor = {
  // 拦截前触发
  invoke(options: CustomRequestOptions) {
    // 添加
    options.url = baseUrl + options.url;
    // 添加 token 请求头标识
    options.header.Authorization = `Bearer ${token}`;
  },
};

export const requestInterceptor = {
  install() {
    // 拦截 request 请求
    uni.addInterceptor("request", httpInterceptor);
    // 拦截 uploadFile 文件上传
    uni.addInterceptor("uploadFile", httpInterceptor);
  },
};

新建 interceptors/index.ts

ts
export { requestInterceptor } from "./request";

修改 main.ts

ts
import { createSSRApp } from "vue";

import App from "./App.vue";
import { requestInterceptor } from "./interceptors";

export function createApp() {
  const app = createSSRApp(App);
  app.use(requestInterceptor);

  return {
    app,
  };
}

(2)路由拦截器 ​

新建 interceptors/route.ts

ts
const loginRoute = "/pages/login/index";

const navigateToInterceptor = {
  invoke({ url }: { url: string }) {
    //可根据登录状态做一些拦截操作
    return true;
  },
};

export const routeInterceptor = {
  install() {
    uni.addInterceptor("navigateTo", navigateToInterceptor);
    uni.addInterceptor("reLaunch", navigateToInterceptor);
    uni.addInterceptor("redirectTo", navigateToInterceptor);
    uni.addInterceptor("switchTab", navigateToInterceptor);
  },
};

导入方式类似于请求拦截器

5. 网络请求 ​

对 uni.request 进行封装,减少重复代码

(1)新建 utils/request.ts ​

ts
// 定义请求配置类型
interface RequestConfig {
  url: string;
  method?:
    | "GET"
    | "POST"
    | "PUT"
    | "DELETE"
    | "OPTIONS"
    | "HEAD"
    | "CONNECT"
    | "TRACE";
  data?: any;
  params?: any; // URL 参数 (uni.request 本身不支持 params,需手动处理)
  header?: Record<string, string>;
  showLoading?: boolean;
  responseType?: "arraybuffer" | "text" | "json";
  [key: string]: any; // 允许其他自定义属性
}

// 定义响应数据结构(根据后端接口约定调整)
interface ResponseData<T = any> {
  code: number;
  msg: string;
  data: T;
}

// 创建请求实例
class Request {
  // 核心请求方法
  request<T = any>(config: RequestConfig): Promise<T> {
    // 合并配置
    let mergedConfig: RequestConfig = {
      method: "GET",
      showLoading: false,
      ...config,
      header: { ...config.header },
    };

    // 处理 URL 参数(手动拼接)
    if (mergedConfig.params) {
      const params = new URLSearchParams(mergedConfig.params).toString();
      mergedConfig.url += `?${params}`;
      delete mergedConfig.params;
    }

    // 显示 Loading
    if (mergedConfig.showLoading) {
      uni.showLoading({ title: "加载中...", mask: true });
    }

    // 发送请求
    return new Promise((resolve, reject) => {
      uni.request({
        url: mergedConfig.url,
        method: mergedConfig.method,
        data: mergedConfig.data,
        header: mergedConfig.header,
        responseType: mergedConfig.responseType,
        success: async (res) => {
          try {
            const data = res.data as ResponseData<T>;

            resolve(data.data);
          } catch (err) {
            reject(err);
          }
        },
        fail: (err) => {
          reject(new Error(`网络错误: ${err.errMsg}`));
        },
        complete: () => {
          // 关闭 Loading
          if (mergedConfig.showLoading) {
            uni.hideLoading();
          }
        },
      });
    });
  }

  get<T>(
    url: string,
    params?: Record<string, any>,
    showLoading?: boolean,
  ): Promise<T> {
    return this.request({ method: "GET", url, params, showLoading });
  }

  delete<T>(
    url: string,
    data?: Record<string, any>,
    showLoading?: boolean,
  ): Promise<T> {
    return this.request({ method: "DELETE", url, data, showLoading });
  }

  post<T>(
    url: string,
    data?: Record<string, any>,
    showLoading?: boolean,
  ): Promise<T> {
    return this.request({ method: "POST", url, data, showLoading });
  }

  put<T>(
    url: string,
    data?: Record<string, any>,
    showLoading?: boolean,
  ): Promise<T> {
    return this.request({ method: "PUT", url, data, showLoading });
  }
}

// 创建实例并配置拦截器
const http = new Request();

export default http;

(2)定义 API 接口类型 ​

ts
// api/types.ts

// 登录接口响应数据
export interface LoginResponse {
  userId: string;
  username: string;
  token: string;
}

// 用户信息接口响应数据
export interface UserInfoResponse {
  nickname: string;
  avatar: string;
  email: string;
}

(3)统一管理 API ​

ts
// api/index.ts

import request from "@/utils/request";
import type { LoginResponse, UserInfoResponse } from "./types";

// 登录接口
export const login = (data: { username: string; password: string }) => {
  return request.post<LoginResponse>("/user/login", data, true);
};

6. 微信小程序开启组件按需注入 ​

json
{
  "lazyCodeLoading": "requiredComponents"
}

五、pages.json ​

1. pages ​

每次新建页面,均需在 pages.json 中配置 pages 列表;未在 pages.json -> pages 中注册的页面,uni-app 会在编译阶段进行忽略。

在 pages 文件夹上右击,新建页面,HBuilderX 会自动在 pages.json 中完成页面注册。

配置项中的第一个页面,作为当前工程的首页(启动页)

提示:

  1. 删除或修改页面时,记得在 pages.json 中同步修改

  2. 新建页面后,需在编译器中点击重新运行编译

如果想取消原生导航栏

json
"pages": [{
  "path": "pages/index/index",
  "style": {
    "navigationStyle": "custom" //取消原生导航
  }
},
],

2. tabBar ​

json
"tabBar": {
  "color": "#7A7E83",
  "selectedColor": "#3cc51f",
  "borderStyle": "black",
  "backgroundColor": "#ffffff",
  "height": "50px",
  "fontSize": "10px",
  "iconWidth": "24px",
  "spacing": "3px",
  "list": [
    {
      "text": "菜谱",
      "pagePath": "pages/index/index",
      "iconPath": "static/tabs/menus.png",
      "selectedIconPath": "static/tabs/menus-active.png"
    },
    {
      "text": "电影",
      "pagePath": "pages/message/index",
      "iconPath": "static/tabs/movie.png",
      "selectedIconPath": "static/tabs/movie-active.png"
    }
  ]
}

提示:

(1)tabBar 中的 list 是一个数组,只能配置最少 2 个、最多 5 个 tab,tab 按数组的顺序排序。

(2)tabbar 切换第一次加载时可能渲染不及时,可以在每个 tabbar 页面的 onLoad 生命周期里先弹出一个等待雪花(hello uni-app 使用了此方式)

(3)tabbar 的页面展现过一次后就保留在内存中,再次切换 tabbar 页面,只会触发每个页面的 onShow,不会再触发 onLoad。

(4)顶部的 tabbar 目前仅微信小程序上支持。需要用到顶部选项卡的话,建议不使用 tabbar 的顶部设置,而是自己做顶部选项卡,可参考 hello uni-app->模板->顶部选项卡。

3. globalStyle ​

用于设置应用的状态栏、导航条、标题、窗口背景色等。

json
"globalStyle": {
  "navigationBarTextStyle": "white",
  "navigationBarTitleText": "网易云音乐",
  "navigationBarBackgroundColor": "#d43c33",
  "backgroundColor": "#FFFFFF",
  "maxWidth": 375
},

更多配置:https://uniapp.dcloud.net.cn/collocation/pages.html#globalstyle

六、使用 ​

1. 生命周期 ​

(1)应用的生命周期(在 App.vue 页面定义) ​

  • onLaunch:当 uni-app 初始化完成时触发(全局只触发一次)
  • onShow:当 uni-app 启动,或从后台进入前台显示
  • onHide:当 uni-app 从前台进入后台
  • onError:当 uni-app 报错时触发

其他的看文档:https://uniapp.dcloud.io/collocation/frame/lifecycle?id=应用生命周期

(2)页面的生命周期 ​

  • onLoad:监听页面加载,其参数为上个页面传递的数据(用于页面传参),在该生命周期中获取接口数据
  • onReady:监听页面渲染完成(只会触发一次)
  • onShow:监听页面显示,页面每次出现在屏幕上触发
  • onHide:监听页面隐藏
  • onUnload:监听页面卸载
  • onPullDownRefresh:监听下拉事件
  • onReachBottom:监听触底事件

其他的看文档:https://uniapp.dcloud.io/collocation/frame/lifecycle?id=页面生命周期

2. 下拉刷新 ​

一般不配置全局下拉刷新,哪个页面需要就配置哪个页面的刷新

(1)需要在 pages.json 里,找到当前页面的 pages 节点,并在 style 选项中开启 enablePullDownRefresh。

json
{
  "path": "pages/message/index",
  "style": {
    "enablePullDownRefresh": true
  }
}

(2)在 js 中定义 onPullDownRefresh 处理函数(和 onload 生命周期函数同级),监听用户页面下拉刷新事件。

当处理完数据后,调用 uni.stopPullDownRefresh() 停止刷新动作

js
onPullDownRefresh() {
  console.log('触发了下拉刷新');
  setTimeout(() => {
    uni.stopPullDownRefresh()
  }, 2000)
},

(3)可以通过触发点击事件,调用 uni.startPullDownRefresh(OBJECT) 来模拟用户的下拉刷新

3. 上拉加载 ​

(1)配置页面上拉触底事件触发时距页面底部距离

json
"globalStyle": {
  "onReachBottomDistance": 50
},

(2)在 js 中定义 onReachBottom 处理函数(和 onload 生命周期函数同级),监听用户页面上拉加载事件。

js
onReachBottom() {
  console.log('上拉')
},

4. 数据缓存 ​

(1)异步存储 ​

js
uni.setStorage({
  key: "id",
  data: 80,
  success() {
    console.log("存储成功");
  },
});

(2)异步获取 ​

js
uni.getStorage({
  key: "id",
  success(res) {
    console.log("获取成功", res.data);
  },
});

(3)同步存储 ​

js
try {
  uni.setStorageSync("storage_key", "hello");
} catch (e) {
  // error
}

(4)同步获取 ​

js
try {
  const value = uni.getStorageSync("storage_key");
  if (value) {
    console.log(value);
  }
} catch (e) {
  // error
}

(5)异步删除 ​

js
uni.removeStorage({
  key: "storage_key",
  success: function (res) {
    console.log("success");
  },
});

(6)同步删除 ​

js
try {
  uni.removeStorageSync("storage_key");
} catch (e) {
  // error
}

(7)异步清空 ​

js
uni.clearStorage();

(8)同步清空 ​

js
try {
  uni.clearStorageSync();
} catch (e) {
  // error
}

注意:

  • H5 端为 localStorage,浏览器限制 5M 大小,是缓存概念,可能会被清理
  • App 端为原生的 plus.storage,无大小限制,不是缓存,是持久化
  • 各个小程序端为其自带的 storage api,数据存储生命周期跟小程序本身一致,即除用户主动删除或超过一定时间被自动清理,否则数据都一直可用。
  • 微信小程序单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB。
  • 支付宝小程序单条数据转换成字符串后,字符串长度最大 200 * 1024。同一个支付宝用户,同一个小程序缓存总上限为 10MB。
  • 百度、字节跳动小程序文档未说明大小限制

5. 路由跳转 ​

(1)保留当前页面,跳转到应用内的某个页面 ​

js
uni.navigateTo({ url: `../login/login?id=${value}` });

参数通过 ? 拼接在 url 上,新页面在 onLoad 生命周期获取。

js
onLoad(options) {
  console.log(options) //{id: "80"}
}

提示:不要将过多的信息存储在 url 上,可传递 Id 等关键信息,然后使用 pinia 存储全部数据,使用 Id 去找相关信息

(2)关闭当前页面,跳转到应用内的某个页面 ​

js
uni.redirectTo();

(3)关闭所有页面,打开到应用内的某个页面 ​

js
uni.reLaunch();

(4)跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 ​

路径不能带参数,可以将值进行数据缓存

js
uni.switchTab();

提示:tabBar 页面通过 uni.navigateTo 跳转到其他页面,是会保留当前页面,所以当使用 uni.switchTab 跳转回来时,是不会触发 onLoad 钩子函数。只会触发 onShow 钩子函数

(5)关闭当前页面,返回上一页面或多级页面 ​

js
uni.navigateBack({ delta: 1 });

6. 发布/订阅 ​

  • 发布:uni.$emit
  • 订阅:uni.$on
  • 取消订阅:uni.$off
  • 只订阅一次:uni.$once

7. Pinia ​

uni-app 内置了 Pinia,不需要额外安装,如果使用 VScode 开发,还需手动安装 pinia(与 vue 一样,注意版本,目前 2.1.7)

(1)在项目根目录新建 store 文件夹 ​

用来存放状态管理相关数据

(2)在 main.js 中编写以下代码: ​

js
import App from "./App";
import { createSSRApp } from "vue";
import * as Pinia from "pinia";

export function createApp() {
  const app = createSSRApp(App);
  app.use(Pinia.createPinia());
  return {
    app,
    Pinia, // 此处必须将 Pinia 返回
  };
}

(3)首先创建一个 Store: ​

js
// stores/counter.js
import { defineStore } from "pinia";

export const useCounterStore = defineStore("counter", {
  state: () => {
    return { count: 0 };
  },
  // 也可以这样定义
  // state: () => ({ count: 0 })
  actions: {
    increment() {
      this.count++;
    },
  },
});

(4)使用 ​

vue
<template>
  <view>
    <text>{{ count }}</text>
    <button @click="increment">按钮</button>
  </view>
</template>

<script setup>
import { storeToRefs } from "pinia";
import { useCounterStore } from "@/stores/counter";

const counterStore = useCounterStore();
const { count } = storeToRefs(counterStore);
const { increment } = counterStore;
</script>

七、打包发布 ​

1. 分包 ​

在 pages.json 文件中配置

属性类型必填描述平台兼容
subPackagesObject Array否分包加载配置H5 不支持
preloadRuleObject否分包预下载规则微信小程序

subPackages:

属性类型是否必填描述
rootString是子包的根目录
pagesArray是子包由哪些页面组成,参数同 pages

preloadRule:

字段类型必填默认值说明
packagesString Array是无进入页面后预下载分包的 root 或 name。__APP__ 表示主包。
networkString否wifi在指定网络下预下载,可选值为:all(不限网络)、wifi(仅 wifi 下预下载)

App 下开启分包,除在 pages.json 中配置分包规则外,还需要在 manifest 中设置在 app 端开启分包设置,详见:https://uniapp.dcloud.io/collocation/manifest?id=app-vue-optimization

注意:

  • subPackages 里的 pages 的路径是 root 下的相对路径,不是全路径。
  • 微信小程序每个分包的大小是 2M,总体积一共不能超过 20M。
  • 百度小程序每个分包的大小是 2M,总体积一共不能超过 8M。
  • 支付宝小程序每个分包的大小是 2M,总体积一共不能超过 8M。
  • QQ 小程序每个分包的大小是 2M,总体积一共不能超过 24M。
  • 抖音小程序每个分包的大小是 2M,总体积一共不能超过 16M(抖音小程序基础库 1.88.0 及以上版本开始支持,抖音小程序开发者工具请使用大于等于 2.0.6 且小于 3.0.0 的版本)。
  • 快手小程序每个分包的大小是 2M,总体积一共不能超过 24M。
  • 分包下支持独立的 static 目录,用来对静态资源进行分包。
  • uni-app 内支持对微信小程序、QQ 小程序、百度小程序、支付宝小程序、抖音小程序(HBuilderX 3.0.3+)、快手小程序分包优化,即将静态资源或者 js 文件放入分包内不占用主包大小。
  • 针对 vendor.js 过大的情况可以使用运行时压缩代码:HBuilderX 创建的项目勾选运行-->运行到小程序模拟器-->运行时是否压缩代码

使用方法:假设支持分包的 uni-app 目录结构如下

text
┌─pages
│ ├─index
│ │ └─index.vue
│ └─login
│ └─login.vue
├─pagesA
│ ├─static
│ └─list
│ └─list.vue
├─pagesB
│ ├─static
│ └─detail
│ └─detail.vue
├─static
├─main.js
├─App.vue
├─manifest.json
└─pages.json

则需要在 pages.json 中填写

json
{
  "pages": [{
    "path": "pages/index/index",
    "style": { ...}
  }, {
    "path": "pages/login/login",
    "style": { ...}
  }],
  "subPackages": [{
    "root": "pagesA",
    "pages": [{
      "path": "list/list",
      "style": { ...}
    }]
  }, {
    "root": "pagesB",
    "pages": [{
      "path": "detail/detail",
      "style": { ...}
    }]
  }],
  "preloadRule": {
    "pagesA/list/list": {
      "network": "all",
      "packages": ["__APP__"]
    },
    "pagesB/detail/detail": {
      "network": "all",
      "packages": ["pagesA"]
    }
  }
}

2. 打包 ​

打包前一定要把历史包删除,否则可能遇到意想不到的错误

(1)小程序打包发布 ​

1:在 manifest.json 中配置小程序 AppID,并开启 ES6 转 ES5 等功能

2:在微信公众平台,小程序中配置服务器域名白名单

3:点击发行按钮后,会在项目的目录 unpackage/dist/build/mp-weixin 生成微信小程序项目代码

4:在微信小程序开发者工具中,导入生成的微信小程序项目,点击微信开发工具的上传

(2)H5 打包 ​

步骤一:在 manifest.json 进行 h5 配置,配置页面标题,index.html 模板、路由模式

步骤二:点击发行 -> 网站,H5 原生版

步骤三:根据导出的路径,将静态资源配置到服务器上

HBuilderX 提示项目导出 h5 成功,输出路径为 unpackage/dist/build/h5

(3)App 打包 ​

步骤一:在 manifest.json 进行基础配置,配置 AppID,如果没有的话就登录创建然后重新获取

步骤二:选择 App 图标配置,在自动生成图标下选择 logo,然后点击自动生成所有图标并替换

步骤三:App 启动界面配置,可以选择自定义启动图

步骤四:App 模块配置,点击需要用到的权限,比如用到了通讯录和地图,就勾选起来

App 模块配置面板:勾选 Contact(通讯录)、Maps(地图)并填写高德地图的 appkey_ios 与 appkey_android

步骤五:选择发行 -> 原生 App 云打包。选择 Android 包,还是 iOS 包,然后配置自有证书(自有证书企业用的,可使用公共测试证书,不过有下载次数限制)。点击打包。

步骤六:打包成功后,会返回一个地址,这时使用二维码生成器将地址转为二维码