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 支持
- 热重载:实时预览开发效果
技术栈
| 技术 | 版本 | 说明 |
|---|---|---|
| Vue | 3.x | 渐进式框架 |
| Vite | 5.x | 构建工具 |
| TypeScript | 5.x | 类型安全 |
| UniApp | 3.x | 跨平台框架 |
| wot-design-uni | 1.x | UI 组件库(70+ 组件) |
| Pinia | 2.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:
- 发行 -> 原生 App-云打包
- 选择平台(Android/iOS)
- 配置证书和图标
- 点击打包
相关链接
- 源码地址:Gitee / GitHub
- 在线演示:https://app.youlai.tech
- UniApp 文档:https://uniapp.dcloud.net.cn
- wot-design-uni 文档:https://wot-design-uni.pages.dev
- 构建教程:从0到1构建 UniApp 跨平台脚手架
