uai-app和vue区别差异
·
我们可以从实际开发流程的每个环节,详细对比 uni-app 和 Vue 的核心差异。两者虽语法同源,但因定位(通用Web vs 跨端)不同,在项目结构、API、组件、路由等方面存在本质区别。
🧠 开发思路
Vue
- 核心思路:围绕 Web DOM 构建单页应用(SPA),专注于Web端的组件化开发,通过虚拟DOM优化渲染效率。
- 关注点:Web端的交互体验、浏览器兼容性、前端工程化(如构建工具、代码分割)。
uni-app
- 核心思路:“一套代码,多端运行”,基于Vue语法,但需同时兼容Web、小程序、App等多端特性。
- 关注点:跨端兼容性(条件编译)、各端原生能力调用、性能优化(如App端原生渲染、小程序分包)。
🔑 核心概念
Vue
- 核心概念:组件化、虚拟DOM、响应式数据(Proxy/Object.defineProperty)、Vue Router(路由)、Pinia(状态管理)。
- 渲染底层:依赖Web DOM,通过操作DOM元素更新页面。
uni-app
- 核心概念:除Vue的核心概念外,新增:
- 条件编译:通过
#ifdef、#ifndef等指令,为不同端编写专属代码。 - 原生组件:
view、text、image等跨端组件(替代Web的div、span)。 - 页面生命周期:
onLoad、onShow、onHide等(兼容小程序/App的页面逻辑)。
- 条件编译:通过
- 渲染底层:
- Web端:Web DOM(同Vue);
- 小程序端:转换为对应平台的原生组件;
- App端:默认WebView渲染,可选 uvue原生渲染(直接调用iOS/Android原生控件)。
🚀 第一步:项目初始化
📁 1. 创建项目目录
Vue
- 创建工具:Vite(推荐)或 Vue CLI。
- 命令示例:
npm create vite@latest my-vue-app -- --template vue - 初始目录:
my-vue-app/ ├── src/ │ ├── components/ # 组件 │ ├── views/ # 页面 │ ├── App.vue # 根组件 │ └── main.js # 入口文件 ├── index.html # HTML模板 └── package.json
uni-app
- 创建工具:HBuilderX(官方推荐,可视化操作)或 uni CLI(命令行)。
- 命令示例(uni CLI):
npx degit dcloudio/uni-preset-vue#vite my-uni-app - 初始目录(跨端特有结构):
my-uni-app/ ├── src/ │ ├── pages/ # 页面(需在pages.json注册) │ ├── static/ # 静态资源(图片、字体等) │ ├── components/ # 组件 │ ├── App.vue # 应用配置(生命周期、全局样式) │ ├── main.js # 入口文件 │ └── pages.json # 【核心】页面路由、窗口样式、tabbar配置 ├── manifest.json # 【核心】各端配置(AppID、权限、原生插件) └── package.json
📦 2. 项目结构规划
Vue
- 结构逻辑:按Web应用功能划分(如
views、components、router、store),无需考虑跨端。 - 关键文件:
router/index.js(路由配置)、store/index.js(状态管理)。
uni-app
- 结构逻辑:按跨端需求划分,需重点关注:
pages.json:统一管理所有端的页面路由、窗口样式(如导航栏颜色、下拉刷新)。manifest.json:配置各端的专属信息(如微信小程序AppID、Android权限)。- 条件编译目录:可创建
platforms/mp-weixin等目录,存放端专属代码。
📦 第二步:安装项目依赖
🔧 1. 安装生产依赖
Vue
- 核心依赖:
vue、vue-router(路由)、pinia(状态管理)。 - 可选依赖:
axios(HTTP请求)、element-plus(Web UI库)、sass(CSS预处理器)。 - 示例:
npm install vue vue-router pinia axios
uni-app
- 核心依赖:
@dcloudio/uni-app(uni-app核心)、@dcloudio/uni-mp-weixin(小程序端适配)等(根据目标端选择)。 - 可选依赖:
- HTTP请求:不能直接用
axios(部分端不支持),需用uni.request或封装@dcloudio/uni-ajax。 - UI库:需用跨端UI库,如
uView Plus、uni-ui(替代Web的Element Plus)。 - 状态管理:仍可用
pinia,但需配合uni.setStorageSync做跨端持久化。
- HTTP请求:不能直接用
- 示例:
npm install @dcloudio/uni-app uview-plus pinia
🔧 2. 安装开发依赖
Vue
- 核心依赖:
vite(构建工具)、@vitejs/plugin-vue(Vue插件)、eslint、prettier。 - 示例:
npm install -D vite @vitejs/plugin-vue eslint prettier
uni-app
- 核心依赖:
@dcloudio/vite-plugin-uni(uni-app构建插件)、@dcloudio/types(uni-app类型定义)。 - 示例:
npm install -D @dcloudio/vite-plugin-uni @dcloudio/types
🤔 为什么选择这些技术栈?
Vue
- 选择
vue-router、pinia:Web生态成熟,专注于单页应用的路由和状态管理。 - 选择
axios:Web端HTTP请求的标准库,支持拦截器、取消请求等高级功能。
uni-app
- 选择
uni.request替代axios:兼容所有端(Web、小程序、App),无需处理跨端适配。 - 选择
uView Plus:专为uni-app设计,组件样式和API在各端一致。 - 选择
pinia+uni.setStorageSync:既保留Vue的状态管理逻辑,又能实现跨端数据持久化。
⚙️ 第三步:配置开发环境
📝 1. 更新package.json的脚本
Vue
- 脚本逻辑:仅针对Web端,分为开发、构建、预览。
- 示例:
{ "scripts": { "dev": "vite", // 启动Web开发服务器 "build": "vite build", // 构建Web生产版本 "preview": "vite preview"// 预览构建结果 } }
uni-app
- 脚本逻辑:按端拆分,每个端有独立的开发和构建命令。
- 示例:
{ "scripts": { "dev:h5": "uni -p h5", // 开发H5端 "dev:mp-weixin": "uni -p mp-weixin", // 开发微信小程序 "dev:app": "uni -p app", // 开发App端 "build:h5": "uni build -p h5", // 构建H5端 "build:mp-weixin": "uni build -p mp-weixin", // 构建微信小程序 "build:app": "uni build -p app" // 构建App端 } }
📝 2. 创建Prettier配置文件
Vue & uni-app
- 配置基本一致:都可通过
.prettierrc配置代码格式化规则。 - uni-app额外注意:需在配置中忽略
manifest.json、pages.json等uni-app核心配置文件(避免格式化破坏结构)。 - 示例:
{ "semi": false, "singleQuote": true, "ignorePath": ".gitignore" }
📝 3. 创建环境变量文件
Vue
- 文件命名:
.env(通用)、.env.development(开发)、.env.production(生产)。 - 变量前缀:需以
VITE_开头(Vite规定)。 - 示例(
.env.development):VITE_API_BASE_URL=http://localhost:3000/api
uni-app
- 文件命名:支持按端拆分,如
.env.mp-weixin(微信小程序环境)、.env.app(App端环境)。 - 变量前缀:需以
VITE_或UNI_开头。 - 示例(
.env.mp-weixin):UNI_API_BASE_URL=https://api.example.com/mp
🎯 第四步:创建基础类型定义
📝 1. 创建通用类型
Vue
- 类型范围:针对Web API和Vue生态,如
Router、PiniaStore、AxiosResponse。 - 示例(
src/types/index.ts):export interface User { id: number; name: string; } export interface ApiResponse<T> { code: number; data: T; message: string; }
uni-app
- 类型范围:除Vue的类型外,需包含 uni-app API类型(如
UniRequestOptions、UniLoginSuccess)和 端专属类型。 - 示例(
src/types/index.ts):// 引入uni-app类型定义 import type { UniRequestOptions } from '@dcloudio/types'; export interface User { id: number; name: string; } // 封装uni.request的响应类型 export interface UniApiResponse<T> { code: number; data: T; message: string; }
🔧 第五步:创建API服务层
📝 1. 创建HTTP客户端配置
Vue
- 实现方式:用
axios封装,支持拦截器、baseURL配置。 - 示例(
src/utils/request.ts):import axios from 'axios'; const request = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 10000 }); // 请求拦截器 request.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) config.headers.Authorization = `Bearer ${token}`; return config; }); // 响应拦截器 request.interceptors.response.use( res => res.data, err => Promise.reject(err) ); export default request;
uni-app
- 实现方式:用
uni.request封装(不能用axios),需兼容各端的请求逻辑。 - 示例(
src/utils/request.ts):const baseURL = import.meta.env.UNI_API_BASE_URL; const request = <T>(options: UniRequestOptions): Promise<UniApiResponse<T>> => { return new Promise((resolve, reject) => { uni.request({ url: 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 as UniApiResponse<T>); } else { reject(res); } }, fail: (err) => reject(err) }); }); }; export default request;
📝 2. 创建认证服务
Vue
- 实现方式:用封装好的
axios调用登录、注册接口,token存储在localStorage。 - 示例(
src/api/auth.ts):import request from '@/utils/request'; export const login = (data: { username: string; password: string }) => { return request.post('/auth/login', data); }; export const register = (data: { username: string; password: string }) => { return request.post('/auth/register', data); };
uni-app
- 实现方式:用封装好的
uni.request调用接口,token存储在uni.setStorageSync(跨端存储);若为小程序/App端,还需调用uni.login获取平台登录凭证。 - 示例(
src/api/auth.ts):import request from '@/utils/request'; // 普通登录 export const login = (data: { username: string; password: string }) => { return request<User>('/auth/login', { method: 'POST', data }); }; // 微信小程序一键登录 export const wechatLogin = () => { return new Promise((resolve, reject) => { uni.login({ provider: 'weixin', success: (loginRes) => { request<User>('/auth/wechat', { method: 'POST', data: { code: loginRes.code } }).then(resolve).catch(reject); }, fail: reject }); }); };
📝 3. 创建文章服务
Vue & uni-app
- 逻辑基本一致:都是调用HTTP接口获取文章列表、详情等。
- 唯一区别:Vue用
axios,uni-app用uni.request。
🎨 第六步:创建全局状态管理
📝 1. 创建认证状态管理
Vue
- 实现方式:用
pinia管理用户信息、token,token持久化到localStorage。 - 示例(
src/stores/auth.ts):import { defineStore } from 'pinia'; import { ref } from 'vue'; export const useAuthStore = defineStore('auth', () => { const user = ref<User | null>(null); const token = ref<string>(localStorage.getItem('token') || ''); const setUser = (newUser: User) => { user.value = newUser; }; const setToken = (newToken: string) => { token.value = newToken; localStorage.setItem('token', newToken); }; const logout = () => { user.value = null; token.value = ''; localStorage.removeItem('token'); }; return { user, token, setUser, setToken, logout }; });
uni-app
- 实现方式:仍用
pinia,但token持久化到uni.setStorageSync(跨端存储)。 - 示例(
src/stores/auth.ts):import { defineStore } from 'pinia'; import { ref } from 'vue'; export const useAuthStore = defineStore('auth', () => { const user = ref<User | null>(null); const token = ref<string>(uni.getStorageSync('token') || ''); const setUser = (newUser: User) => { user.value = newUser; }; const setToken = (newToken: string) => { token.value = newToken; uni.setStorageSync('token', newToken); }; const logout = () => { user.value = null; token.value = ''; uni.removeStorageSync('token'); }; return { user, token, setUser, setToken, logout }; });
📝 2. 创建文章状态管理
Vue & uni-app
- 逻辑基本一致:用
pinia管理文章列表、详情等状态。
🏗️ 第七步:创建基础组件
📝 1. 创建布局组件
Vue
- 组件元素:用Web的
div、header、footer、main等语义化标签。 - 示例(
src/components/Layout.vue):<template> <div class="layout"> <header class="header">头部</header> <main class="main"><slot /></main> <footer class="footer">页脚</footer> </div> </template> <style scoped> .layout { display: flex; flex-direction: column; min-height: 100vh; } .header { height: 60px; background: #333; color: #fff; } .main { flex: 1; padding: 20px; } .footer { height: 40px; background: #eee; } </style>
uni-app
- 组件元素:必须用uni-app的跨端组件
view、text等(不能用Web的div、span)。 - 示例(
src/components/Layout.vue):<template> <view class="layout"> <view class="header">头部</view> <view class="main"><slot /></view> <view class="footer">页脚</view> </view> </template> <style scoped> /* 用rpx单位适配多端屏幕(750rpx = 屏幕宽度) */ .layout { display: flex; flex-direction: column; min-height: 100vh; } .header { height: 120rpx; background: #333; color: #fff; } .main { flex: 1; padding: 40rpx; } .footer { height: 80rpx; background: #eee; } </style>
📝 2. 创建主布局组件
Vue
- 布局逻辑:用
vue-router的<router-view />渲染页面内容。
uni-app
- 布局逻辑:无需
<router-view />,页面内容由pages.json配置的路由自动渲染;主布局通常通过App.vue的全局样式或自定义组件实现。
📝 3. 创建页脚组件
Vue & uni-app
- 逻辑基本一致:用对应框架的组件实现,注意uni-app需用跨端组件和rpx单位。
🔐 第八步:创建认证页面
📝 1. 创建登录页面
Vue
- 页面元素:用
form、input、button等Web表单元素,路由跳转用router.push。 - 示例(
src/views/Login.vue):<template> <div class="login"> <form @submit.prevent="handleLogin"> <input v-model="username" placeholder="用户名" /> <input v-model="password" type="password" placeholder="密码" /> <button type="submit">登录</button> </form> </div> </template> <script setup> import { ref } from 'vue'; import { useRouter } from 'vue-router'; import { useAuthStore } from '@/stores/auth'; import { login } from '@/api/auth'; const router = useRouter(); const authStore = useAuthStore(); const username = ref(''); const password = ref(''); const handleLogin = async () => { const res = await login({ username: username.value, password: password.value }); authStore.setToken(res.data.token); authStore.setUser(res.data.user); router.push('/'); }; </script>
uni-app
- 页面元素:用
form、input、button等uni-app表单组件,路由跳转用uni.switchTab、uni.navigateTo等(不能用router.push)。 - 示例(
src/pages/login/login.vue):<template> <view class="login"> <form @submit="handleLogin"> <input v-model="username" placeholder="用户名" /> <input v-model="password" type="password" placeholder="密码" /> <button form-type="submit">登录</button> </form> <!-- 微信小程序一键登录按钮(条件编译) --> <button v-if="def.mp-weixin" @click="handleWechatLogin">微信一键登录</button> </view> </template> <script setup> import { ref } from 'vue'; import { useAuthStore } from '@/stores/auth'; import { login, wechatLogin } from '@/api/auth'; const authStore = useAuthStore(); const username = ref(''); const password = ref(''); const handleLogin = async () => { const res = await login({ username: username.value, password: password.value }); authStore.setToken(res.data.token); authStore.setUser(res.data.user); uni.switchTab({ url: '/pages/index/index' }); // 跳转到tabbar页面 }; const handleWechatLogin = async () => { const res = await wechatLogin(); authStore.setToken(res.data.token); authStore.setUser(res.data.user); uni.switchTab({ url: '/pages/index/index' }); }; </script>
📝 2. 创建注册页面
Vue & uni-app
- 逻辑同登录页面:Vue用Web表单和
router.push,uni-app用跨端表单和uni.navigateTo。
🏠 第九步:创建首页和文章页面
📝 1. 创建首页组件
Vue
- 页面逻辑:用
axios获取文章列表,用v-for渲染,点击跳转用router-link。 - 示例(
src/views/Home.vue):<template> <div class="home"> <h1>文章列表</h1> <div v-for="article in articles" :key="article.id" class="article-item"> <router-link :to="`/article/${article.id}`"> <h2>{{ article.title }}</h2> <p>{{ article.summary }}</p> </router-link> </div> </div> </template> <script setup> import { ref, onMounted } from 'vue'; import { getArticles } from '@/api/article'; const articles = ref([]); onMounted(async () => { const res = await getArticles(); articles.value = res.data; }); </script>
uni-app
- 页面逻辑:用
uni.request获取文章列表,用scroll-view渲染长列表(优化性能),点击跳转用uni.navigateTo。 - 示例(
src/pages/index/index.vue):<template> <view class="home"> <text class="title">文章列表</text> <!-- scroll-view优化长列表滚动 --> <scroll-view scroll-y class="article-list"> <view v-for="article in articles" :key="article.id" class="article-item" @click="goToDetail(article.id)"> <text class="article-title">{{ article.title }}</text> <text class="article-summary">{{ article.summary }}</text> </view> </scroll-view> </view> </template> <script setup> import { ref, onLoad } from 'vue'; import { getArticles } from '@/api/article'; const articles = ref([]); // 用onLoad替代onMounted(uni-app页面生命周期) onLoad(async () => { const res = await getArticles(); articles.value = res.data; }); const goToDetail = (id: number) => { uni.navigateTo({ url: `/pages/article/detail?id=${id}` }); }; </script>
📝 2. 创建文章详情页面
Vue
- 路由参数:用
useRoute().params获取文章ID。
uni-app
- 路由参数:用
onLoad的参数获取文章ID(如onLoad((options) => { const id = options.id; }))。
📝 3. 创建文章编辑页面
Vue & uni-app
- 逻辑同登录页面:注意uni-app需用跨端组件和API。
🔗 第十步:配置路由系统
📝 1. 创建路由配置
Vue
- 实现方式:用
vue-router单独创建路由配置文件。 - 示例(
src/router/index.ts):import { createRouter, createWebHistory } from 'vue-router'; import Home from '@/views/Home.vue'; import Login from '@/views/Login.vue'; const routes = [ { path: '/', component: Home }, { path: '/login', component: Login }, { path: '/article/:id', component: () => import('@/views/ArticleDetail.vue') } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router;
uni-app
- 实现方式:无需单独的路由文件,所有路由在
pages.json中配置。 - 示例(
src/pages.json):{ "pages": [ { "path": "pages/index/index", // 首页(第一个为默认页) "style": { "navigationBarTitleText": "首页" } }, { "path": "pages/login/login", "style": { "navigationBarTitleText": "登录" } }, { "path": "pages/article/detail", "style": { "navigationBarTitleText": "文章详情" } } ], "tabBar": { // 底部tabbar配置 "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/user/index", "text": "我的" } ] } }
📝 2. 创建路由保护组件
Vue
- 实现方式:用
vue-router的beforeEach全局前置守卫。 - 示例(
src/router/index.ts):router.beforeEach((to, from, next) => { const token = localStorage.getItem('token'); if (to.path !== '/login' && !token) { next('/login'); } else { next(); } });
uni-app
- 实现方式:没有内置的路由守卫,需通过
App.vue的onLaunch、onShow或页面的onLoad实现。 - 示例(
src/App.vue):<script setup> import { onLaunch } from '@dcloudio/uni-app'; onLaunch(() => { const token = uni.getStorageSync('token'); if (!token) { uni.reLaunch({ url: '/pages/login/login' }); } }); </script>
🎨 第十一步:创建样式和主题
📝 1. 创建全局样式
Vue
- 样式单位:用
px、rem、em等Web常用单位。 - 样式文件:在
src/styles/global.css中定义,在main.js中引入。 - 示例:
* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Arial, sans-serif; }
uni-app
- 样式单位:推荐用
rpx(响应式像素,750rpx = 屏幕宽度,自动适配多端)。 - 样式文件:在
src/styles/global.css中定义,在App.vue的<style>中引入。 - 示例:
/* 全局样式 */ page { font-family: Arial, sans-serif; background: #f5f5f5; } .container { padding: 40rpx; }
📝 2. 更新主入口文件
Vue
- 入口文件:
src/main.js,引入路由、状态管理、全局样式。 - 示例:
import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; import pinia from './stores'; import './styles/global.css'; const app = createApp(App); app.use(router); app.use(pinia); app.mount('#app');
uni-app
- 入口文件:
src/main.js,引入状态管理、全局样式(无需引入路由)。 - 示例:
import { createSSRApp } from 'vue'; import App from './App.vue'; import pinia from './stores'; import './styles/global.css'; export function createApp() { const app = createSSRApp(App); app.use(pinia); return { app }; }
🚀 第十二步:启动和测试
📝 1. 启动开发服务器
Vue
- 启动命令:
npm run dev,在浏览器中访问http://localhost:5173。
uni-app
- 分端启动:
- H5端:
npm run dev:h5,在浏览器访问; - 微信小程序:
npm run dev:mp-weixin,用微信开发者工具打开项目目录; - App端:
npm run dev:app,用HBuilderX连接真机或模拟器预览。
- H5端:
📝 2. 功能测试清单
Vue
- 测试重点:Web端的交互、浏览器兼容性、响应式布局。
uni-app
- 测试重点:
- 多端兼容性:H5、小程序、App端的功能是否一致;
- 端专属功能:如微信小程序的一键登录、App端的原生渲染;
- 性能:长列表滚动、动画是否流畅。
🎯 第十三步:优化和部署
📝 1. 性能优化
Vue
- 优化方向:代码分割、路由懒加载、组件缓存(
keep-alive)、图片懒加载。
uni-app
- 优化方向:
- 小程序端:分包加载(在
pages.json中配置subPackages)、减少主包体积; - App端:用 uvue 替代普通Vue页面(原生渲染,提升性能);
- 通用:图片压缩、使用
scroll-view优化长列表、避免频繁的uni.setStorageSync。
- 小程序端:分包加载(在
📝 2. 构建生产版本
Vue
- 构建命令:
npm run build,生成dist目录,部署到Web服务器。
uni-app
- 分端构建:
- H5端:
npm run build:h5,生成dist/build/h5目录,部署到Web服务器; - 微信小程序:
npm run build:mp-weixin,生成dist/build/mp-weixin目录,用微信开发者工具上传代码; - App端:
npm run build:app,用HBuilderX打包成ipa(iOS)或apk(Android)。
- H5端:
📝 3. 部署配置
Vue
- 部署方式:将
dist目录部署到Nginx、Apache等Web服务器,配置反向代理解决跨域。
uni-app
- 部署方式:
- H5端:同Vue;
- 小程序端:上传到微信公众平台、支付宝开放平台等,提交审核;
- App端:上传到App Store(iOS)、应用宝(Android)等应用市场。
总结:核心差异对比表
| 环节 | Vue | uni-app |
|---|---|---|
| 定位 | 通用Web框架 | 跨端框架(Web/小程序/App) |
| 渲染底层 | Web DOM | Web端:DOM;小程序:原生组件;App:WebView/uvue原生 |
| 项目结构 | src/views、router/index.js | src/pages、pages.json、manifest.json |
| 路由 | vue-router | pages.json配置 |
| HTTP请求 | axios | uni.request |
| 组件 | div、span等Web组件 | view、text等跨端组件 |
| 样式单位 | px、rem | rpx(推荐) |
| 状态管理 | pinia + localStorage | pinia + uni.setStorageSync |
| 启动/构建 | 仅Web端 | 分端(H5/小程序/App) |
更多推荐


所有评论(0)