2025 年必看!uni-app 结合 VSCode 实现高效跨平台开发入门

前言

行业的凛冬已至,现在越来越多的前端岗位要求全干,其中小程序开发是其中必不可少的一环。尽管 uni-app 仍存在一些不足和问题,但它的一个显著优势在于能够解决大部分的兼容性问题,从而大幅提升了开发效率。

2024/02/19我写了篇 微信小程序《入门级教程》,其中文章开头提到uni-app在招聘市场上已鲜少提及,但在2025年招聘岗位上,uni-app的身影又活跃起来(🤣🤣🤣)。

目前使用uni-app的一个很大的问题,就是周边生态跟不上,很多第三方库都不维护了(毕竟谁都不能一直用爱发电),我也看到了一些库通过看广告和打赏的方式勉强维持着更新。

本篇文章为了实用性,不会过多介绍第三方库的使用,尽量只介绍官方的。

一、快速上手

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

1.创建uni-app

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

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

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

2. 运行uni-app

(1)浏览器运行

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

(2)真机运行

步骤一:开启USB调试

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

步骤二:进行授权

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

步骤三:运行程序

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

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

下载微信开发者工具:developers.weixin.qq.com/miniprogram...

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

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

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

3. 安装常用插件

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

二、VSCode改造

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

1. TypeScript

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

  1. 安装
js 复制代码
yarn add @types/node -D 
yarn add @dcloudio/types -D
  1. 新建tsconfig.json
js 复制代码
{
  "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"]
}

注意:uni-app中的路径别名@指的是项目的根目录,而非src目录,因此"paths": { "@/*": ["./*"] }

2. ESlint、Prettier

  1. 安装
js 复制代码
//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
  1. 新建.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
    },
};
  1. 新建 .prettierrc
js 复制代码
{
    "endOfLine": "auto",
    "printWidth": 120,
    "semi": true,
    "singleQuote": true,
    "tabWidth": 2,
    "trailingComma": "all",
    "bracketSpacing": true
}
  1. 新建 .prettierignore
js 复制代码
# 忽略格式化文件 (根据项目需要自行添加)
node_modules
dist
  1. 重启vscode使配置生效

  2. 配置package.json

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

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

三、差异点

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. 引用

对于静态文件使用绝对路径(从根目录开始)

js 复制代码
<image src="/static/index/banner.png"></image>

但 js 文件不支持绝对路径的方式引入,可使用相对路径,或路径别名@(指向项目根目录)

js 复制代码
import { transformUrl } from '@/utils/url';

5. 条件编译

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

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

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

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

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

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

js 复制代码
┌─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 目录的条件编译

四、全局配置

1. H5跨域

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

方案二:使用Chrome代理插件

安装完扩展后,选择开启

2. 小程序配置域名白名单

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

以微信小程序为例,登录小程序后台 ,在开发 -> 开发管理 -> 开发设置 -> 服务器域名中进行配置。

注意点:

  1. 域名不能使用IP地址或localhost,且不能带端口号

  2. 域名必须经过ICP备案

  3. 对于每个接口,分别可以配置最多20个域名

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

3. 拦截器

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

1. 请求拦截器

可做接口权限等相关配置

新建interceptors/request.ts

js 复制代码
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

js 复制代码
export { requestInterceptor } from './request'

修改main.ts

js 复制代码
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

js 复制代码
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)
  },
}

修改 interceptors/index.ts

js 复制代码
export { routeInterceptor } from './route';
export { requestInterceptor } from './request';

修改main.ts

js 复制代码
import { createSSRApp } from 'vue'

import App from './App.vue'
import { requestInterceptor,routeInterceptor } from './interceptors'

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

  return {
    app,
  }
}

5. 网络请求

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

  1. 新建utils/request.ts
js 复制代码
// 定义请求配置类型
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;

这里我没有封装请求拦截器,因为拦截功能已通过uni.addInterceptor实现。

  1. 定义 API 接口类型
js 复制代码
// api/types.ts

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

// 用户信息接口响应数据
export interface UserInfoResponse {
  nickname: string;
  avatar: string;
  email: string;
}
  1. 统一管理 API
js 复制代码
// 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,showLoading:true);
};

五、pages.json

1. pages

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

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

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

提示:

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

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

2. tabBar

js 复制代码
"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

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

js 复制代码
"globalStyle": {
  "navigationBarTextStyle": "white",
  "navigationBarTitleText": "网易云音乐",
  "navigationBarBackgroundColor": "#d43c33",
  "backgroundColor": "#FFFFFF",
  "maxWidth": 375
},

更多配置:uniapp.dcloud.net.cn/collocation...

六、使用

1. 生命周期

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

  • onLaunch:当uni-app初始化完成时触发(全局只触发一次)

  • onShow:当uni-app启动,或从后台进入前台显示

  • onHide:当uni-app从前台进入后台

  • onError:当uni-app报错时触发

其他的看文档:uniapp.dcloud.io/collocation...

(2)页面的生命周期

  • onLoad:监听页面加载,其参数为上个页面传递的数据(用于页面传参),在该生命周期中获取接口数据

  • onReady:监听页面渲染完成(只会触发一次)

  • onShow:监听页面显示,页面每次出现在屏幕上触发

  • onHide:监听页面影藏

  • onUnload:监听页面卸载

  • onPullDownRefresh:监听下拉事件

  • onReachBottom:监听触底事件

其他的看文档:uniapp.dcloud.io/collocation...

2.下拉刷新

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

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

js 复制代码
{
  "path": "pages/message/index",
  "style":{
    "enablePullDownRefresh":true
  }

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

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

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

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

3.上拉加载

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

js 复制代码
"globalStyle": {
  "onReachBottomDistance": 50
},

(2)在js中定义onReachBottom处理函数,监听用户页面上拉加载事件。

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()

提示:

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

2.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,不需要额外安装,在HBuilderX目录HBuilderX\plugins\hbuilderx-language-services\builtin-dts\uniapp@vue3\node_modules目录下

  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 返回
	};
}
  1. 首先创建一个 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++;
		},
	},
});
  1. 使用
js 复制代码
<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文件中配置

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

subPackages:

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

preloadRule:

字段 类型 必填 默认值 说明
packages StringArray 进入页面后预下载分包的 root 或 name。APP 表示主包。
network String wifi 在指定网络下预下载,可选值为:all(不限网络)、wifi(仅wifi下预下载)

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

注意:

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 目录结构如下

js 复制代码
┌─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 中填写

js 复制代码
{
	"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原生版

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

(3)App打包

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

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

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

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

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

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

结尾

文章内容如果有不准确或不及时的地方,欢迎大家在评论区指出。如果后续本篇文章对大家有帮助,收藏多的话,将会一直更新下去。

相关推荐
csdn_HPL2 小时前
SpringBoot + Vue 实现云端图片上传与回显(基于OSS等云存储)
vue.js·spring boot·后端
苹果酱05672 小时前
Vue3 源码解析(六):响应式原理与 reactive
java·vue.js·spring boot·mysql·课程设计
Monly213 小时前
Uniapp:创建项目
uni-app
清晨細雨3 小时前
uniapp微信小程序:WIFI设备配网之TCP/UDP开发AP配网
前端·物联网·小程序·uni-app
寒寒_3 小时前
uni-app 安卓10以上上传原图解决方案
uni-app
樊小肆3 小时前
Vue3 在线 PDF 编辑 1.0 批注回显与文字批注优化
前端·vue.js
用户70548322592583 小时前
无需花钱购买域名服务器!使用 VuePress + Github 30分钟搭建属于自己的博客网站(保姆级教程)
vue.js
许妹l3 小时前
我理解的 v-if 指令的转换过程
vue.js
许妹l3 小时前
我理解的 v-for 指令的转换过程
vue.js
wangyongquan3 小时前
vue组件通信【父子,子父,vuex】
前端·vue.js