一套代码两端跑:用 uni-app 搓个跨端小工具

举报
海是岛思念的泪 发表于 2026/09/20 09:58:08 2026/09/20
【摘要】 用 uni-app 写一个小记账工具,一套 Vue 代码同时编译到 H5、微信小程序和 App,用条件编译处理平台差异,省去重复开发。

公司要做个内部小工具,领导一句"手机和网页都要能看",换以前我得写一套 Vue、再写一套小程序,双倍工作量。后来试了 uni-app——它让你用写 Vue 的方式,把同一份代码编译到 H5、微信小程序、App 甚至鸿蒙。手艺活还是 Vue 那套,但产出能多端跑。这篇我拿一个"随手记账"的小工具当例子,把最关键的几个点讲透。

image.png

一、先想清楚它能省多少事

我做的这个记账工具,需求很朴素:记一笔收入和支出、看当月汇总、数据存本地。如果分开写:

平台 单独写要搞的东西
H5 网页 Vue 工程 + 路由 + 本地存储
微信小程序 小程序框架 + wx.setStorage + 页面栈
App 另一套打包流程

用 uni-app 之后,这三份"壳"由编译器生成,我只写一份 pages 和 store。当然平台差异不可能完全没有,但 uni-app 提供了条件编译,哪段代码只在某个平台生效就套一层标记,其余平台编译时直接剔除。

二、工程结构和页面

用官方脚手架起一个项目后,目录长这样:

├─ pages/
│  ├─ index/index.vue      # 记账首页
│  └─ list/list.vue        # 明细列表
├─ store/
│  └─ bill.js              # 账单一一存本地
├─ App.vue
├─ main.js
└─ pages.json              # 页面路由和窗口配置

首页很简单,一个表单加一个汇总卡片。uni-app 的 API 是统一的,比如存数据用 uni.setStorageSync:

<!-- pages/index/index.vue -->
<template>
  <view class="page">
    <view class="card">
      <text class="title">本月收支</text>
      <text class="amount">收入 ¥{{ income }} / 支出 ¥{{ expense }}</text>
    </view>

    <view class="form">
      <input v-model="amount" type="digit" placeholder="金额" />
      <picker :range="types" @change="onTypeChange">
        <view class="picker">{{ types[typeIndex] }}</view>
      </picker>
      <button @click="addBill">记一笔</button>
    </view>

    <button @click="goList">查看明细</button>
  </view>
</template>

<script setup>
import { ref, computed } from 'vue'
import { useBillStore } from '@/store/bill'

const amount = ref('')
const types = ['支出', '收入']
const typeIndex = ref(0)
const bill = useBillStore()

const income = computed(() => bill.monthIncome)
const expense = computed(() => bill.monthExpense)

function onTypeChange(e) { typeIndex.value = e.detail.value }

function addBill() {
  const val = parseFloat(amount.value)
  if (!val || val <= 0) { uni.showToast({ title: '金额不对', icon: 'none' }); return }
  bill.add({ amount: val, type: types[typeIndex.value], date: Date.now() })
  amount.value = ''
  uni.showToast({ title: '已记下', icon: 'success' })
}
function goList() { uni.navigateTo({ url: '/pages/list/list' }) }
</script>

这里用到的 uni.showToast、uni.navigateTo、uni.setStorageSync 都是 uni-app 的跨端 API,编译到哪都能用,不用我去记小程序的 wx.xxx 还是网页的 alert。

三、把数据存本地,用 Pinia 风格的 store

uni-app 里也可以用 Pinia,我习惯把账单读写封装进一个 store,页面只调方法:

// store/bill.js
import { defineStore } from 'pinia'

export const useBillStore = defineStore('bill', {
  state: () => ({ list: uni.getStorageSync('bills') || [] }),
  getters: {
    monthIncome: (s) => s.list.filter(b => b.type === '收入')
      .reduce((sum, b) => sum + b.amount, 0),
    monthExpense: (s) => s.list.filter(b => b.type === '支出')
      .reduce((sum, b) => sum + b.amount, 0),
  },
  actions: {
    add(bill) {
      this.list.push(bill)
      uni.setStorageSync('bills', this.list)  // 落本地,下次打开还在
    },
  },
})

小程序和 App 上 uni.setStorageSync 底层会映射到各自的本地存储;H5 上就是 localStorage。同一行代码,三端行为一致,这就是跨端框架最香的地方。

四、平台差异用条件编译兜

总有些东西平台不一样。比如微信小程序想要转发分享,要写 onShareAppMessage;H5 上想接个第三方统计 SDK,小程序里又没有 window。这时候用条件编译:

// #ifdef H5
import './h5-analytics'   // 只在 H5 编译进这段代码
// #endif

// #ifdef MP-WEIXIN
export function shareConfig() {
  return { title: '我的记账本', path: '/pages/index/index' }
}
// #endif

编译器看到 // #ifdef H5 就知道:这段只在编 H5 时保留,编小程序时整段删掉。反过来 #ifndef 是"除了某某平台都保留"。把平台相关代码圈在这类标记里,主体逻辑就能保持干净。

五、几个落地时的小提醒

  1. 样式用 rpx 不用 px:rpx 会根据屏幕宽度自适应,750rpx 等于屏宽,写一套布局多端都不歪。
  2. 别用浏览器特有 API:比如 document、window 在小程序里不存在,真要用就包条件编译或找 uni 的等价 API。
  3. 真机调试优先:小程序和 App 的行为 simulator 和真机常有出入,我一般写完就在真机上点一遍。
  4. 组件库能省很多:uni-ui 或 uView 这类现成组件直接装,表单、弹窗、下拉都不用自己造。

总结一下

uni-app 不是万能的——特别复杂的原生能力(比如底层蓝牙、特定硬件交互)还是得写原生插件。但对于"一套业务逻辑、多端展示"的普通工具类应用,它确实把重复劳动砍掉了一大半。我那个记账工具,H5 版给同事在电脑上用、小程序版自己手机上记,代码就一份,改一处两端都生效。

如果你的需求也是"多个端都要、逻辑高度重合",真心建议试一把 uni-app,把精力留给业务逻辑本身,而不是耗在重复适配上。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。