Skip to content

vue-uniapp-template 移动端

项目简介

vue-uniapp-template 是基于 Vue 3 和 UniApp 构建的跨平台移动应用模板,一套代码可同时编译到 H5、小程序、App 等多个平台。

项目特色

📱 跨平台支持

  • H5:支持浏览器和微信公众号
  • 小程序:微信、支付宝、百度、字节跳动等
  • App:Android、iOS 原生应用
  • 快应用:华为、小米等厂商快应用

🎨 UI 组件

  • wot-design-uni:基于 Wot Design 规范的高质量组件库(70+ 组件)
  • 自定义组件:业务场景定制组件
  • 响应式设计:适配各种屏幕尺寸
  • 暗黑模式:支持深色主题切换
  • 国际化支持:内置多语言支持
  • 自定义主题:灵活的主题定制能力

⚡ 开发体验

  • Vue 3 Composition API:现代化的开发方式
  • TypeScript:类型安全(可选)
  • HBuilderX:官方 IDE 支持
  • 热重载:实时预览开发效果

技术栈

技术版本说明
Vue3.x渐进式框架
Vite5.x构建工具
TypeScript5.x类型安全
UniApp3.x跨平台框架
wot-design-uni1.xUI 组件库(70+ 组件)
Pinia2.x状态管理
UnoCSS-原子化 CSS
uni-request-网络请求

快速开始

环境准备

bash
# Node.js 版本
node -v  # 需要 Node 16+

# 安装 HBuilderX(推荐)
# 下载地址:https://www.dcloud.io/hbuilderx.html

# 或使用 Vue CLI
npm install -g @vue/cli

项目启动

bash
# 1. 打开 HBuilderX
# 2. 文件 -> 导入 -> 从本地目录导入
# 3. 选择项目目录
# 4. 运行 -> 运行到浏览器/模拟器/手机
bash
# 克隆项目
git clone https://gitee.com/youlaiorg/vue-uniapp-template.git

# 进入项目目录
cd vue-uniapp-template

# 安装依赖
npm install

# 启动 H5
npm run dev:h5

# 启动微信小程序
npm run dev:mp-weixin

# 启动 App
npm run dev:app

接口配置

修改 src/config/config.js

javascript
export default {
  // 开发环境
  development: {
    baseURL: 'http://localhost:8080',
    timeout: 10000
  },
  // 生产环境
  production: {
    baseURL: 'https://api.yourdomain.com',
    timeout: 10000
  }
}

项目结构

vue-uniapp-template
├── pages                 # 页面目录
│   ├── index            # 首页
│   ├── login            # 登录页
│   ├── user             # 用户中心
│   └── ...
├── components           # 组件目录
│   ├── common           # 公共组件
│   └── business         # 业务组件
├── static               # 静态资源
│   ├── images           # 图片
│   ├── icons            # 图标
│   └── ...
├── store                # 状态管理
│   ├── modules          # 模块
│   └── index.js
├── utils                # 工具函数
│   ├── request.js       # 请求封装
│   ├── auth.js          # 认证工具
│   └── ...
├── uni_modules          # uni 插件
├── App.vue              # 应用配置
├── main.js              # 入口文件
├── manifest.json        # 应用配置
└── pages.json           # 页面路由

核心功能

用户登录

vue
<template>
  <view class="login-container">
    <wd-form ref="formRef" :model="form">
      <wd-cell-group border>
        <wd-input
          v-model="form.username"
          label="用户名"
          placeholder="请输入用户名"
          clearable
        />
        <wd-input
          v-model="form.password"
          type="password"
          label="密码"
          placeholder="请输入密码"
          show-password
          clearable
        />
      </wd-cell-group>
      <view class="button-group">
        <wd-button type="primary" size="large" block @click="handleLogin">
          登录
        </wd-button>
      </view>
    </wd-form>
  </view>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useUserStore } from '@/store/user'

const userStore = useUserStore()
const form = ref({
  username: '',
  password: ''
})

const handleLogin = async () => {
  try {
    await userStore.login(form.value)
    uni.navigateTo({ url: '/pages/index/index' })
  } catch (error) {
    uni.showToast({
      title: '登录失败',
      icon: 'none'
    })
  }
}
</script>

<style scoped lang="scss">
.login-container {
  padding: 40rpx;
}

.button-group {
  margin-top: 40rpx;
}
</style>

网络请求

javascript
// utils/request.js
import config from '@/config/config'

const request = (options) => {
  return new Promise((resolve, reject) => {
    uni.request({
      url: config.baseURL + options.url,
      method: options.method || 'GET',
      data: options.data || {},
      header: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + uni.getStorageSync('token')
      },
      success: (res) => {
        if (res.statusCode === 200) {
          resolve(res.data)
        } else {
          reject(res)
        }
      },
      fail: (err) => {
        reject(err)
      }
    })
  })
}

export default request

状态管理

javascript
// store/modules/user.js
import { defineStore } from 'pinia'
import request from '@/utils/request'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: uni.getStorageSync('token') || '',
    userInfo: null
  }),

  actions: {
    async login(loginForm) {
      const res = await request({
        url: '/api/v1/auth/login',
        method: 'POST',
        data: loginForm
      })
      this.token = res.data.accessToken
      uni.setStorageSync('token', this.token)
    },

    async getUserInfo() {
      const res = await request({
        url: '/api/v1/users/me'
      })
      this.userInfo = res.data
    },

    logout() {
      this.token = ''
      this.userInfo = null
      uni.removeStorageSync('token')
    }
  }
})

平台差异处理

条件编译

vue
<template>
  <view>
    <!-- #ifdef H5 -->
    <view>这段代码只在 H5 显示</view>
    <!-- #endif -->

    <!-- #ifdef MP-WEIXIN -->
    <view>这段代码只在微信小程序显示</view>
    <!-- #endif -->

    <!-- #ifdef APP-PLUS -->
    <view>这段代码只在 App 显示</view>
    <!-- #endif -->
  </view>
</template>

<script>
// #ifdef H5
console.log('H5 环境')
// #endif

// #ifdef MP-WEIXIN
console.log('微信小程序环境')
// #endif
</script>

API 差异

javascript
// 获取系统信息
const systemInfo = uni.getSystemInfoSync()
console.log('平台:', systemInfo.platform)
console.log('屏幕宽度:', systemInfo.screenWidth)

// 导航跳转
uni.navigateTo({ url: '/pages/detail/detail?id=1' })

// 显示提示
uni.showToast({
  title: '操作成功',
  icon: 'success'
})

// 请求权限(仅 App)
// #ifdef APP-PLUS
uni.requestPermission({
  permissionID: 'android.permission.CAMERA'
})
// #endif

常用组件

列表展示

vue
<template>
  <view>
    <u-list @scrolltolower="loadMore">
      <u-list-item v-for="item in list" :key="item.id">
        <view class="item">
          <text>{{ item.title }}</text>
        </view>
      </u-list-item>
    </u-list>
  </view>
</template>

<script setup>
import { ref } from 'vue'

const list = ref([])
const page = ref(1)

const loadMore = async () => {
  // 加载更多数据
  page.value++
  const res = await request({
    url: '/api/v1/items/page',
    data: { pageNum: page.value }
  })
  list.value.push(...res.data.list)
}
</script>

图片上传

vue
<template>
  <u-upload
    :fileList="fileList"
    :maxCount="9"
    @afterRead="afterRead"
    @delete="deleteFile"
  />
</template>

<script setup>
import { ref } from 'vue'

const fileList = ref([])

const afterRead = (file) => {
  // 上传到服务器
  uni.uploadFile({
    url: config.baseURL + '/api/v1/files/upload',
    filePath: file.url,
    name: 'file',
    success: (res) => {
      const data = JSON.parse(res.data)
      fileList.value.push({
        url: data.data.url,
        name: file.name
      })
    }
  })
}

const deleteFile = (index) => {
  fileList.value.splice(index, 1)
}
</script>

打包发布

H5 打包

bash
npm run build:h5

生成的文件在 dist/build/h5 目录,可直接部署到服务器。

小程序打包

bash
npm run build:mp-weixin

生成的文件在 dist/build/mp-weixin 目录,使用微信开发者工具打开并上传。

App 打包

使用 HBuilderX:

  1. 发行 -> 原生 App-云打包
  2. 选择平台(Android/iOS)
  3. 配置证书和图标
  4. 点击打包

相关链接

基于 MIT 许可发布