2025-06-10

一、引言

随着小程序功能越来越多,项目包体积也随之膨胀。包体过大会导致:

  • 下载/更新耗时增长:用户首次下载或更新时,等待时间过长,容易流失用户。
  • 加载速度变慢:App 启动或切换页面时,卡顿现象明显。
  • 流量及存储成本增加:对用户体验和运营成本都有较大影响。

针对这些痛点,本文将从 uniapp 项目结构、常见冗余内容、压缩策略等方面进行讲解,并通过“图解+代码示例”来深入剖析如何在保留功能的前提下,大幅度减少包体大小。


二、uniapp 项目体积组成与常见冗余

在开始优化之前,先了解一下典型 uniapp 小程序项目包体的组成。从最细粒度来看,主要包含以下几部分:

  1. 页面及组件代码

    • .vue 文件中的模板、样式(CSS/SCSS)、逻辑(JavaScript/TypeScript)
    • 公共组件、三方 UI 库(如 uView、Vant 等)
  2. 资源文件

    • 图片(PNG/JPG/WEBP/SVG)
    • 字体文件(TTF、woff 等)
    • 视频/音频(若有的话)
  3. 第三方依赖

    • NPM 模块、uni\_modules 插件
    • 小程序官方/第三方 SDK(如地图、支付、社交等)
  4. 打包产物

    • 小程序平台所需的 app.jsonproject.config.json 等配置文件
    • 编译后生成的 .wxss.wxml.js 文件

2.1 常见冗余示例

  • 未压缩或未转换的图片:原始拍摄的高清图片往往几 MB,若直接放入项目,包体暴增。
  • 未使用的字体/图标:引入了整个字体文件(如 Iconfont 全量 TTF),实际只用到部分图标。
  • 无效/重复的 CSS 样式:项目中遗留的无用样式、重复导入的样式文件。
  • 不必要的大体积 NPM 包:某些第三方库自身依赖过大,实际使用功能很少,却引入整个包。
  • 调试代码和日志:未删除的 console.logdebugger 代码,在编译时会增加 JS 文件体积。

三、瘦身思路与流程(图解)

为了更清晰地展示瘦身的整体流程,下面用一张流程图来概括整个优化思路。

┌────────────────────────┐
│ 1. 分析项目体积来源   │
│   └─ 运行打包分析工具 │
│       · 查看各模块占比│
└──────────┬───────────┘
           │
           ▼
┌────────────────────────┐
│ 2. 针对性优化资源文件 │
│   · 图片压缩/转 WebP    │
│   · 精灵图/图标字体     │
│   · 移除无用资源       │
└──────────┬───────────┘
           │
           ▼
┌────────────────────────┐
│ 3. 优化依赖与代码      │
│   · 剔除无用依赖       │
│   · 按需加载/组件拆分   │
│   · 删除调试/日志代码   │
└──────────┬───────────┘
           │
           ▼
┌────────────────────────┐
│ 4. 构建及平台定制化    │
│   · 开启压缩/混淆      │
│   · 开启代码分包(微信)│
│   · 生成最终包并复测   │
└────────────────────────┘
图1:uniapp 小程序瘦身整体流程(上图为示意 ASCII 流程图)

从流程中可以看到,项目瘦身并非一蹴而就,而是一个「分析→资源→依赖/代码→构建」的迭代过程。下面我们逐步展开。


四、核心优化策略与代码示例

4.1 分析项目体积来源

在执行任何操作之前,先要明确当前包体中哪些资源或代码块占据了主体体积。常见工具有:

  • 微信开发者工具自带“编译体积”面板

    • 打开项目后,切换到“工具”→“构建npm”,构建完成后,在微信开发者工具右侧的“编译”面板下就可以看到每个 JS 包/资源的大小占比。
  • 第三方打包分析

    • 对于 HBuilderX 编译到小程序的项目,也可以通过 dist/build/mp-weixin 下的产物配合工具(如 webpack-bundle-analyzer)进行体积分析。
示例:微信开发者工具查看页面包体结构
微信开发者工具编译体积面板示意微信开发者工具编译体积面板示意

图示示例,仅为参考,实际界面请以微信开发者工具为准

通过分析,我们往往可以发现:

  • 某个页面的 JS 包远大于其他页面,可能是因为引用了体积巨大的 UI 组件库。
  • 某些资源(如视频、字体)占比超过 50%。
  • 重复引用模块导致代码多次打包。

代码示例:使用 miniprogram-build-npm (示例仅供思路参考)

# 安装微信小程序 NPM 构建工具(若已经安装,可以跳过)
npm install -g miniprogram-build-npm

# 在项目根目录执行
miniprogram-build-npm --watch
该工具会在项目中生成 miniprogram_npm,并自动同步依赖。配合微信开发者工具的「构建 npm」功能,更方便观察依赖包大小。

4.2 资源文件优化

4.2.1 图片压缩与格式转换

  1. 批量压缩工具

    • 可使用 tinypngImageOptimimgmin 等命令行/可视化工具,减小 PNG/JPG 的体积。
    • 例如使用 pngquant(命令行):

      # 安装 pngquant(macOS / Linux)
      brew install pngquant
      
      # 批量压缩:将 images/ 目录下所有 PNG 压缩到 output/ 目录
      mkdir -p output
      pngquant --quality=65-80 --output output/ --ext .png --force images/*.png
  2. 转为 WebP 格式

    • WebP 在保持画质的前提下,通常能比 PNG/JPG 小 30–50%。
    • 在 uniapp 中,可以在项目打包后,将 dist/build/mp-weixin/static/images 下的 JPG/PNG 批量转换为 WebP,然后修改引用。
  3. 按需使用 SVG

    • 对于图标类资源,如果是简单路径、几何图形,建议使用 SVG。可直接内嵌或做为 iconfont 字体。

示例:使用 Node.js 脚本批量转换图片为 WebP

// convert-webp.js
// 需要先安装:npm install sharp glob
const sharp = require('sharp');
const glob = require('glob');

glob('static/images/**/*.png', (err, files) => {
  if (err) throw err;
  files.forEach(file => {
    const outPath = file.replace(/\.png$/, '.webp');
    sharp(file)
      .toFormat('webp', { quality: 80 })
      .toFile(outPath)
      .then(() => {
        console.log(`转换完成:${outPath}`);
      })
      .catch(console.error);
  });
});

执行:

node convert-webp.js

转换完毕后,记得在 .vue 或 CSS 中,将原先的 .png/.jpg 路径改为 .webp

4.2.2 图标字体与精灵图

  • Iconfont 在线生成子集

    • 在阿里巴巴矢量图标库(Iconfont)中,只选取项目实际用到的图标,导出时仅打包对应字符,避免全量 TTF/WOFF。
  • CSS Sprite 将多个小图合并一张

    • 对于大量相似且尺寸较小的背景图,可使用 spritesmithgulp-spritesmith 等工具,一键合并,减少请求。

示例:使用 gulp-spritesmith 生成 sprite

// gulpfile.js
const gulp = require('gulp');
const spritesmith = require('gulp.spritesmith');

gulp.task('sprite', function () {
  const spriteData = gulp.src('static/icons/*.png')
    .pipe(spritesmith({
      imgName: 'sprite.png',
      cssName: 'sprite.css',
      padding: 4,            // 图标之间的间距,防止相互干扰
      cssFormat: 'css'
    }));

  // 输出雪碧图
  spriteData.img.pipe(gulp.dest('static/sprites/'));
  // 输出对应的样式文件
  spriteData.css.pipe(gulp.dest('static/sprites/'));
});

执行 gulp sprite 后,static/sprites/sprite.pngsprite.css 会自动生成。
在项目中引入 sprite.png 以及对应的 CSS,即可通过 class 控制不同背景位置。

4.2.3 移除无用资源

  • 定期审查 static 目录:删除不再使用的图片、视频、音频等。
  • 版本控制合并时注意清理:一些临时测试资源(如测试图片、测试音频)在合并后未清理,需时常检查。

4.3 依赖与代码层面优化

4.3.1 剔除无用依赖

  1. 分析 NPM 依赖体积

    • 部分第三方包会携带大量冗余内容(比如示例、文档等),可通过 npm prune --production 或手动删除无关目录。
  2. 按需引入组件库

    • 如果仅用到部分组件,尽量不要引入整个 UI 框架。以 uView 为例,按需引用可极大缩小依赖体积。
    • 示例:只使用 uView 的 Button 和 Icon 组件:

      // main.js
      import Vue from 'vue';
      // 只引入按钮和图标
      import { uButton, uIcon } from 'uview-ui';
      Vue.component('u-button', uButton);
      Vue.component('u-icon', uIcon);
    • 注意:不同框架的按需引入方式不尽相同,请查阅相应文档。
  3. 替换体积大于功能的库

    • 比如,如果只是想做一个简单的日期格式化,用 moment.js(体积约 150KB)就显得冗余,推荐改用 dayjs(体积约 2KB+插件)。
    • 示例:

      npm uninstall moment
      npm install dayjs
      // 旧代码(moment)
      import moment from 'moment';
      const today = moment().format('YYYY-MM-DD');
      
      // 优化后(dayjs)
      import dayjs from 'dayjs';
      const today = dayjs().format('YYYY-MM-DD');

4.3.2 删除调试与日志代码

  • Vue/uniapp 环境判断:只在开发模式打印日志,生产模式移除 console.log

    // utils/logger.js
    const isDev = process.env.NODE_ENV === 'development';
    export function log(...args) {
      if (isDev) {
        console.log('[LOG]', ...args);
      }
    }
  • 打包时删除 console

    • vue.config.js(HBuilderX 项目可在 unpackage/uniapp/webpack.config.js)中开启 terser 插件配置,将 consoledebugger 自动剔除:

      // vue.config.js
      module.exports = {
        configureWebpack: {
          optimization: {
            minimizer: [
              new (require('terser-webpack-plugin'))({
                terserOptions: {
                  compress: {
                    drop_console: true,
                    drop_debugger: true
                  }
                }
              })
            ]
          }
        }
      };

4.3.3 代码分包与按需加载

  • 微信小程序分包

    • 对于体积较大的页面,可将其拆分到分包(subPackage),首包体积不超过 2MB。
    • 示例 app.json

      {
        "pages": [
          "pages/index/index",
          "pages/login/login"
        ],
        "subPackages": [
          {
            "root": "pages/heavy",
            "pages": [
              "video/video",
              "gallery/gallery"
            ]
          }
        ],
        "window": {
          "navigationBarTitleText": "uniapp瘦身示例"
        }
      }
  • 条件动态加载组件

    • 对于不常访问的模块,通过 import() 图语法实现懒加载,仅在真正需要时才加载。
    • 示例:点击按钮后再加载视频组件

      <template>
        <view>
          <button @click="loadVideo">加载视频页面</button>
          <component :is="VideoComponent" v-if="VideoComponent" />
        </view>
      </template>
      
      <script>
      export default {
        data() {
          return {
            VideoComponent: null
          };
        },
        methods: {
          async loadVideo() {
            // 动态 import
            const { default: vc } = await import('@/components/VideoPlayer.vue');
            this.VideoComponent = vc;
          }
        }
      };
      </script>

      这样在初始加载时不会打包 VideoPlayer.vue,只有点击后才会请求并加载对应 JS 文件和资源。


4.4 构建及平台定制化

4.4.1 开启压缩与混淆

  • HBuilderX 打包设置

    • 打开 HBuilderX,选择“发行”→“小程序-微信”,在“设置”中勾选“压缩代码”、“合并文件”、“删除注释”等选项。
    • 这些选项会在最终生成的 .wxss.js 文件中剔除空格、注释并合并多余的文件,进一步缩小体积。
  • Vue CLI 项目
    若你使用 vue-cli-plugin-uni,可以在 vue.config.js 中做如下配置:

    module.exports = {
      productionSourceMap: false, // 线上不生成 SourceMap
      configureWebpack: {
        optimization: {
          minimizer: [
            new (require('terser-webpack-plugin'))({
              terserOptions: {
                compress: {
                  drop_console: true,
                  drop_debugger: true
                }
              }
            })
          ]
        }
      }
    };

4.4.2 针对不同平台的定制化

  • 微信小程序(MP-WEIXIN)

    • app.json 中配置 subPackages,并在 project.config.json 中配置 miniprogramRoot 目录。
    • manifest.json 中关闭调试模式("mp-weixin": { "appid": "...", "setting": { "urlCheck": false }}),减少额外校验。
  • 支付宝小程序/百度小程序等

    • 不同平台对 API 调用和文件目录结构稍有差异,需分别检查对应平台下的 dist/build/mp-alipaydist/build/mp-baidu 下的产物,确保没有冗余资源。

五、图解示例

下面以“图片压缩 & 代码分包”为例,通过简单的图解说明它们对包体大小的影响。

5.1 图片压缩前后对比

  ┌───────────────────────────┐         ┌───────────────────────────┐
  │ Image_Original.png (2MB) │  压缩  │ Image_Optimized.webp (400KB) │
  └───────────────────────────┘  →    └───────────────────────────┘

          │                                     │
┌───────────────────────────────┐       ┌───────────────────────────────┐
│ 小程序包体:                    │       │ 小程序包体:                    │
│ - 页面 JS:800KB              │       │ - 页面 JS:800KB              │
│ - 图片资源:2MB               │       │ - 图片资源:400KB             │
│ - 第三方依赖:1.2MB           │       │ - 第三方依赖:1.2MB           │
│ = 总计:4MB                   │       │ = 总计:2.4MB                 │
└───────────────────────────────┘       └───────────────────────────────┘
图2:压缩图片对包体体积的直接影响
从上图可见,将一个 2MB 的 PNG 压缩/转换为 400KB 的 WebP 后,包体整体从 4MB 降至 2.4MB,节省了 1.6MB,用户体验显著提升。

5.2 代码分包前后(以微信小程序为例)

┌───────────────────────────────────────┐
│             首包(主包)              │
│  ┌───────────────────────────────┐    │
│  │ pages/index/index.js (600KB)  │    │
│  │ pages/login/login.js (300KB)  │    │
│  │ component/NavBar.js (200KB)   │    │
│  └───────────────────────────────┘    │
│  图片、样式、依赖等:400KB           │    │
│  → 首包总计:1.5MB (超出微信首包限制) │    │
└───────────────────────────────────────┘
↓ 拆分 “重” 页面 → 分包加载
┌───────────────────────────────────────┐
│             首包(主包)              │
│  ┌───────────────────────────────┐    │
│  │ pages/index/index.js (600KB)  │    │
│  │ pages/login/login.js (300KB)  │    │
│  └───────────────────────────────┘    │
│  图片、样式、依赖等:400KB           │    │
│  → 首包总计:1.3MB (已在限制内)      │    │
└───────────────────────────────────────┘
         ↓
┌───────────────────────────────────────┐
│             分包: heavyPages         │
│  ┌───────────────────────────────┐    │
│  │ pages/heavy/video.js (800KB)  │    │
│  │ pages/heavy/gallery.js (700KB)│    │
│  │ 相关资源等:500KB             │    │
│  → 分包总计:2MB                   │    │
└───────────────────────────────────────┘
图3:微信小程序分包示意
将大体积页面(如含大量视频/图片的页面)拆分到 subPackages 后,主包大小从 1.5MB 降到 1.3MB,满足微信首包最大 2MB 限制。用户在打开主包时,只加载必要内容;访问重资源页面时再加载对应分包。

六、进阶优化与细节建议

6.1 代码切分与组件抽离

  • 公共组件单独打包:将通用组件(如导航栏、底部 Tab)提取到一个公共包,使用时统一引用,避免重复打包。
  • 页面懒加载:对于 Tab 栏页面,可暂时只渲染主页,其他页面仅在首次切换时才编译、渲染,以提升首屏速度。

6.2 智能删除无用样式

  • PurifyCSS / UnCSS 思路:针对编译后生成的 CSS(例如 common/index.wxss),将项目中所有 .vue.js 文件中未引用的 CSS 选择器从最终打包中移除。

    注意:由于 uniapp 使用了类似 scoped CSS 的机制,需结合打包产物来做分析。

6.3 CDN 化静态资源(仅限 H5 不推荐用于小程序)

  • 对于 H5 端可将大文件(如音视频)上传到 CDN,项目中只存放小体积占位文件;小程序端建议使用微信云存储或其他静态资源仓库。

6.4 开启小程序兼容性方案

  • 基础库版本选择:选择较新版本的微信基础库,避免因为兼容旧版本而引入 polyfill,减少无用代码。
  • 去除小程序内置默认样式:通过 app.wxss 中重置常见默认样式,避免因为兼容性自动注入过多样式。

6.5 持续监控与 CI 集成

  • 自动化体积检测:在 CI/CD 流程中(如 GitHub Actions、GitLab CI)集成“构建 + 打包分析”环节,当包体超过预设阈值时发出告警。
  • 日志化记录打包历史:使用简单脚本记录每次构建后主包和分包体积,方便回溯和对比。

七、完整代码示例汇总

以下是一个较为完整的示例,展示了典型项目中如何按上述思路进行配置和调用。部分代码仅作示意,需结合项目实际进行调整。

# 1. 安装常用依赖
npm init -y
npm install uni-app uview-ui dayjs sharp gulp gulp-spritesmith pngquant-cli
// vue.config.js (HBuilderX + uniapp 项目示例)
module.exports = {
  productionSourceMap: false,
  configureWebpack: {
    optimization: {
      minimizer: [
        new (require('terser-webpack-plugin'))({
          terserOptions: {
            compress: {
              drop_console: true,
              drop_debugger: true
            }
          }
        })
      ]
    }
  }
};
// convert-webp.js (批量将 PNG 转 WebP)
const sharp = require('sharp');
const glob = require('glob');

glob('static/images/**/*.png', (err, files) => {
  if (err) throw err;
  files.forEach(file => {
    const outPath = file.replace(/\.png$/, '.webp');
    sharp(file)
      .toFormat('webp', { quality: 80 })
      .toFile(outPath)
      .then(() => {
        console.log(`转换完成:${outPath}`);
      })
      .catch(console.error);
  });
});
// gulpfile.js (生成雪碧图示例)
const gulp = require('gulp');
const spritesmith = require('gulp.spritesmith');

gulp.task('sprite', function () {
  const spriteData = gulp.src('static/icons/*.png')
    .pipe(spritesmith({
      imgName: 'sprite.png',
      cssName: 'sprite.css',
      padding: 4,
      cssFormat: 'css'
    }));

  spriteData.img.pipe(gulp.dest('static/sprites/'));
  spriteData.css.pipe(gulp.dest('static/sprites/'));
});
// app.json (微信小程序分包示例)
{
  "pages": [
    "pages/index/index",
    "pages/login/login"
  ],
  "subPackages": [
    {
      "root": "pages/heavy",
      "pages": [
        "video/video",
        "gallery/gallery"
      ]
    }
  ],
  "window": {
    "navigationBarTitleText": "uniapp瘦身示例"
  }
}
<!-- 示例:按需引入 uView Button & Icon -->
<template>
  <view>
    <u-button type="primary">主要按钮</u-button>
    <u-icon name="home" size="24" />
  </view>
</template>

<script>
import Vue from 'vue';
import { uButton, uIcon } from 'uview-ui';
Vue.component('u-button', uButton);
Vue.component('u-icon', uIcon);

export default {
  name: 'DemoPage'
};
</script>
<!-- 示例:动态加载重资源组件(VideoPlayer.vue) -->
<template>
  <view>
    <button @click="loadVideo">加载视频</button>
    <component :is="VideoComponent" v-if="VideoComponent" />
  </view>
</template>

<script>
export default {
  data() {
    return {
      VideoComponent: null
    };
  },
  methods: {
    async loadVideo() {
      const { default: vc } = await import('@/components/VideoPlayer.vue');
      this.VideoComponent = vc;
    }
  }
};
</script>

八、总结

通过以上流程与示例,可以看到 uniapp 小程序瘦身并不是只做一次简单的图片压缩,而是一个从整体到局部的持续优化过程:

  1. 先“量化”:通过分析工具明确各模块、资源体积占比。
  2. 再“对症下药”:针对性地进行图片压缩、字体优化、精灵图合并;剔除无用依赖;开启代码混淆;按需分包等。
  3. 最后“持续监控”:将打包体积纳入 CI/CD 自动检测,避免后续功能迭代中体积“悄然增长”。

核心目标是“以最小代价换取最佳体验”:既要保证小程序功能完整、交互流畅,又要尽可能减少下载与更新时用户等待时间。希望本文的代码示例、图解示意和详细说明,能让你快速掌握 uniapp 小程序瘦身的核心思路,在项目中灵活运用。

2024-08-27

在uni-app中配置底部导航栏,你需要在 pages.json 文件中设置 tabBar 对象。以下是一个简单的示例:




{
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "UniApp Demo",
    "navigationBarBackgroundColor": "#F8F8F8",
    "backgroundColor": "#F8F8F8"
  },
  "tabBar": {
    "color": "#7A7E83",
    "selectedColor": "#3cc51f",
    "borderStyle": "black",
    "backgroundColor": "#ffffff",
    "list": [
      {
        "pagePath": "pages/home/home",
        "iconPath": "static/img/home.png",
        "selectedIconPath": "static/img/home-selected.png",
        "text": "首页"
      },
      {
        "pagePath": "pages/mine/mine",
        "iconPath": "static/img/mine.png",
        "selectedIconPath": "static/img/mine-selected.png",
        "text": "我的"
      }
    ]
  }
}

在这个配置中:

  • color 是未选中的图标和文本的颜色。
  • selectedColor 是选中的图标和文本的颜色。
  • borderStyle 是底部边框的颜色。
  • backgroundColor 是底部导航栏的背景颜色。
  • list 数组中定义了每个tab的属性,包括页面路径、图标路径(非选中状态)、图标路径(选中状态)和标签文本。

确保你的项目结构中有对应的文件夹和文件,并且图标的路径是正确的。这样你就可以在uni-app项目中使用底部导航栏了。

2024-08-27

在uniapp中使用x-www-form-urlencoded; charset=UTF-8格式发送请求,可以使用uni.request API。以下是一个示例代码:




uni.request({
    url: 'https://your-api-endpoint.com/data', // 你的API接口地址
    method: 'POST',
    header: {
        'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', // 设置请求的 content-type 为 x-www-form-urlencoded
    },
    data: {
        key1: 'value1',
        key2: 'value2'
    },
    success: (res) => {
        console.log('请求成功', res.data);
    },
    fail: (err) => {
        console.error('请求失败', err);
    }
});

在这个例子中,我们设置了请求的方法为POST,并在header中指定了content-typeapplication/x-www-form-urlencoded; charset=UTF-8。data对象中的键值对会被转换成查询字符串格式,并发送到服务器。

注意:在实际开发中,你需要替换urldatasuccess回调中的处理逻辑以满足你的具体需求。

2024-08-27

在微信小程序中使用sm4加密,你可以使用微信小程序的wx.getFileSystemManager来获取文件系统管理器,然后使用sm-crypto库进行加密操作。以下是一个简单的示例:

首先,你需要在小程序的代码中引入sm-crypto库。你可以通过npm或者直接下载sm-crypto的文件来引入。




// 引入CryptoJS
var CryptoJS = require('./crypto-js/crypto-js.js');
 
// 密钥,请使用自己的密钥
var key = CryptoJS.enc.Utf8.parse('12345678');
 
// 需要加密的数据
var data = 'data to encrypt';
 
// 加密
var encrypted = CryptoJS.SM4.encrypt(data, key);
 
// 打印加密结果
console.log(encrypted.toString());
 
// 解密
var decrypted = CryptoJS.SM4.decrypt(encrypted, key);
 
// 打印解密结果
console.log(decrypted.toString(CryptoJS.enc.Utf8));

请确保你的密钥key是正确的,并且是utf8编码的。

注意:由于小程序的环境限制,不是所有的JavaScript库都可以在小程序中使用,因此你需要确保所用的库是兼容微信小程序的。sm-crypto应该是可以使用的,但如果有问题,你可能需要查看该库是否有适合小程序的版本或者修改库的代码以便在小程序中使用。

2024-08-27

在uniapp中生成并保存二维码,可以使用第三方库qrcode来生成二维码图片,然后使用uni.saveImageToPhotosAlbum方法将其保存到用户的相册中。以下是一个简单的示例:

  1. 首先,需要安装qrcode库,可以通过npm安装:



npm install qrcode
  1. 在需要生成二维码的页面中,引入qrcode库,并使用它来生成二维码:



// 引入qrcode库
import QRCode from 'qrcode'
 
export default {
  methods: {
    // 生成二维码并保存到相册
    async generateAndSaveQRCode(text) {
      // 生成二维码
      const qrcodeImage = await QRCode.toDataURL(text, { errorCorrectionLevel: 'H' });
      
      // 将二维码图片转换为图片路径
      const tempFilePath = await this.dataURLToTempFilePath(qrcodeImage);
      
      // 保存图片到相册
      uni.saveImageToPhotosAlbum({
        filePath: tempFilePath,
        success: () => {
          uni.showToast({ title: '保存成功' });
        },
        fail: () => {
          uni.showToast({ title: '保存失败', icon: 'none' });
        }
      });
    },
    
    // 将base64图片转换为临时文件路径
    dataURLToTempFilePath(dataURL) {
      return new Promise((resolve, reject) => {
        const arr = dataURL.split(',');
        const mime = arr[0].match(/:(.*?);/)[1];
        uni.getFileSystemManager().writeFile({
          filePath: `${wx.env.USER_DATA_PATH}/qrcode.png`,
          data: arr[1],
          encoding: 'base64',
          success: res => {
            resolve(`${wx.env.USER_DATA_PATH}/qrcode.png`);
          },
          fail: err => {
            reject(err);
          }
        });
      });
    }
  }
}
  1. 在页面的按钮点击事件中调用generateAndSaveQRCode方法:



<template>
  <view>
    <button @click="generateAndSaveQRCode('https://example.com')">生成并保存二维码</button>
  </view>
</template>

确保在manifest.json中配置了相册权限:




"permission": {
    "scope.writePhotosAlbum": {
        "desc": "你的相册"
    }
}

用户第一次调用保存图片到相册的功能时,将会收到权限申请提示。

2024-08-26

在小程序中使用vant组件库,并实现全局数据共享,分包加载以及tabBar的配置。

首先,确保已经按照vant Weapp的文档安装并引入了vant组件库。




// 在项目根目录下的subpackages.json中配置分包
{
  "pages": [
    "pages/tabBar/tabBar-1/tabBar-1",
    "pages/tabBar/tabBar-2/tabBar-2"
    // ... 其他页面
  ],
  "subPackages": [
    {
      "root": "pages/subpackage",
      "pages": [
        "subpage/subpage"
      ]
    }
  ]
}

app.json中配置tabBar:




{
  "tabBar": {
    "list": [
      {
        "pagePath": "pages/tabBar/tabBar-1/tabBar-1",
        "text": "Tab 1"
      },
      {
        "pagePath": "pages/tabBar/tabBar-2/tabBar-2",
        "text": "Tab 2"
      }
      // ... 其他tab
    ]
  }
}

app.js中设置全局数据共享:




App({
  globalData: {
    userInfo: null
  },
  onLaunch: function () {
    // 小程序初始化时执行
  },
  getUserInfo: function(cb) {
    var that = this
    if (this.globalData.userInfo) {
      typeof cb == "function" && cb(this.globalData.userInfo)
    } else {
      // 调用登录API获取用户信息
      wx.login({
        success: function () {
          wx.getUserInfo({
            success: function (res) {
              that.globalData.userInfo = res.userInfo
              typeof cb == "function" && cb(that.globalData.userInfo)
            }
          })
        }
      })
    }
  }
})

在页面的.json配置中启用分包加载:




{
  "usingComponents": {
    "van-button": "/path/to/vant-weapp/button/index"
  },
  "subpackages": [
    {
      "root": "pages/subpackage",
      "pages": [
        "subpage/subpage"
      ]
    }
  ]
}

在页面的.wxml中使用vant组件:




<van-button type="primary">按钮</van-button>

以上代码展示了如何在小程序中引入vant Weapp组件库,实现全局数据共享,配置分包加载以及tabBar的简单使用。

2024-08-26

在H5页面向小程序发送消息,通常是通过微信提供的wx.miniProgram.postMessage方法实现的。以下是实现这一功能的基本步骤和示例代码:

  1. 在H5页面中,监听适当的事件(如按钮点击),并在事件处理函数中调用wx.miniProgram.postMessage方法。
  2. 在小程序的页面中,监听onMessage事件以接收来自H5页面的消息。

H5页面发送消息的代码示例:




// 当某个事件发生时,比如按钮点击
document.getElementById('your-button').addEventListener('click', function() {
    // 判断当前环境是否为微信小程序
    if (typeof wx !== 'undefined' && typeof wx.miniProgram !== 'undefined') {
        // 向小程序发送数据
        wx.miniProgram.postMessage({
            data: {
                key: 'value' // 需要发送的数据
            },
            success: function(res) {
                console.log('发送成功', res);
            },
            fail: function(err) {
                console.log('发送失败', err);
            }
        });
    } else {
        // 非小程序环境的处理逻辑
    }
});

小程序页面接收消息的代码示例:




Page({
    onLoad: function(options) {
        // 监听H5页面发送的消息
        wx.onMessage(message => {
            console.log('接收到H5页面的消息:', message.data);
            // 处理接收到的数据
        });
    }
});

确保H5页面在微信环境中运行,并且小程序已经打开。当H5页面中的事件被触发时,数据会通过wx.miniProgram.postMessage发送给小程序,小程序的页面通过wx.onMessage监听函数接收这些消息。

2024-08-25

在小程序中生成海报并分享到朋友圈,可以使用canvas绘制图片,然后导出图片保存到本地相册。以下是实现该功能的基本步骤和示例代码:

  1. 在小程序页面的.wxml文件中定义canvas组件。
  2. 使用canvas上下文绘制图片和文字。
  3. 使用canvas提供的toTempFilePath方法导出图片到本地。
  4. 使用微信小程序的wx.saveImageToPhotosAlbum方法将图片保存到相册。

示例代码:




// 在.js文件中
Page({
  onShareTap: function () {
    const ctx = wx.createCanvasContext('myCanvas');
    // 绘制背景图片或形状
    ctx.drawImage('/path/to/background.png', 0, 0, 200, 200);
    // 绘制文字
    ctx.setFontSize(12);
    ctx.setFillStyle('#333');
    ctx.fillText('Hello, MiniProgram', 50, 50);
    // ... 其他绘制内容
    ctx.draw(true, () => {
      ctx.draw(true, () => {
        wx.canvasToTempFilePath({
          canvasId: 'myCanvas',
          success: (res) => {
            const tempFilePath = res.tempFilePath;
            wx.saveImageToPhotosAlbum({
              filePath: tempFilePath,
              success: () => {
                wx.showToast({ title: '保存成功' });
              },
              fail: () => {
                wx.showToast({ title: '保存失败', icon: 'none' });
              }
            });
          },
          fail: () => {
            wx.showToast({ title: '生成图片失败', icon: 'none' });
          }
        });
      });
    });
  }
});

.wxml文件中:




<canvas canvas-id="myCanvas" style="width: 200px; height: 200px;"></canvas>
<button bindtap="onShareTap">分享到朋友圈</button>

确保在小程序的app.json或页面的xxx.json中添加了使用画布的权限:




{
  "permission": {
    "canvas": {
      "desc": "你的信息将用于生成分享图片"
    }
  }
}

注意:实际使用时需要根据自己的需求调整绘制的内容和样式,并确保有对应的图片资源路径。此外,用户在第一次调用保存图片到相册的API时,会收到权限申请,需要用户授权。

2024-08-25

在Vue3和UniApp中,获取页面DOM元素通常可以通过组合式API中的ref属性来实现。以下是一个简单的例子:




<template>
  <view>
    <text ref="textRef">Hello, UniApp!</text>
  </view>
</template>
 
<script setup>
import { ref, onMounted } from 'vue';
 
const textRef = ref(null);
 
onMounted(() => {
  // 使用textRef.value获取DOM元素
  console.log(textRef.value); // 这里会输出DOM元素
});
</script>

在上面的例子中,我们使用了ref属性来为<text>元素创建了一个引用(textRef)。在onMounted生命周期钩子中,我们可以通过textRef.value来访问对应的DOM元素。

请注意,在小程序环境中,因为平台的限制,不是所有的DOM API都可以使用,你可能需要使用小程序提供的API来进行DOM操作,例如使用uni.createSelectorQuery()来选择器查询DOM元素。

2024-08-24

问题解释:

在uniapp中配置了pages.jsontabbar实现了国际化,但是在切换小程序的语言时,tabbar没有实时更新。

解决方法:

  1. 确保在切换语言后,正确地设置了小程序的语言。在uniapp中,可以使用uni.setLocale方法来设置语言。
  2. 在切换语言后,需要调用uni.reLaunch或者uni.switchTab来重启当前页面,以确保tabbar正确渲染。

示例代码:




// 切换语言的函数
function switchLanguage(lang) {
  uni.setLocale({
    lang: lang
  });
  uni.reLaunch({
    url: '/pages/index/index' // 假设重启到首页
  });
}
 
// 调用切换语言的函数
switchLanguage('en'); // 假设切换到英文
  1. 确保在pages.json中配置了正确的tabbar信息,并且对应的语言文件(如i18n)已经被正确地设置。
  2. 如果使用了第三方国际化库,确保库的版本支持小程序的动态语言切换,并且正确地实现了语言的切换逻辑。
  3. 如果以上方法都不能解决问题,可以考虑查看uniapp的官方文档,或者在uniapp社区寻求帮助,也可以检查是否是小程序平台的bug,可以向微信等小程序平台的官方报告问题。