各位老铁,早上好啊!今天咱们唠唠 UniApp 这个 “万能选手”,看看它怎么在 Web、小程序、App 之间玩转代码复用和版本管理,让咱们开发效率蹭蹭往上涨。
开场白:UniApp 是个啥?
简单来说,UniApp 就是一个使用 Vue.js 语法开发多端应用的框架。你写一套代码,它就能编译成 Web 页面、微信/支付宝/百度小程序、iOS/Android App。是不是听着就很省心?
代码复用:一份代码,多处开花
UniApp 的核心思想就是 “Write Once, Run Everywhere” (一次编写,到处运行)。它是怎么做到的呢?主要靠以下几个法宝:
- 组件化开发:
- UniApp 基于 Vue.js,所以组件化是基本操作。咱们把页面拆分成一个个独立的组件,比如 Header、Footer、List Item 等等。这些组件可以在不同的页面和平台上复用。
- 举个例子,假设咱们有个通用的按钮组件
MyButton.vue
:
<template>
<button class="my-button" @click="handleClick">{{ text }}</button>
</template>
<script>
export default {
props: {
text: {
type: String,
default: '按钮'
}
},
methods: {
handleClick() {
this.$emit('click'); // 触发点击事件,父组件可以监听
}
}
};
</script>
<style scoped>
.my-button {
background-color: #409EFF;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
</style>
* 这个 `MyButton` 组件可以在 Web 页面、小程序和 App 中直接使用,只需要在需要的地方引入即可。
- 条件编译:
- 不同平台总有些差异,比如 API 不一样,或者 UI 展现形式不一样。这时候就需要用到条件编译。UniApp 允许咱们针对不同的平台编写不同的代码。
- 条件编译使用
#ifdef
和#ifndef
指令,根据不同的平台标识来决定是否编译某段代码。
<template>
<view>
<text>Hello UniApp</text>
<!-- #ifdef MP-WEIXIN -->
<button @click="navigateToMiniProgram">跳转到小程序</button>
<!-- #endif -->
<!-- #ifdef H5 -->
<button @click="navigateToWebPage">跳转到网页</button>
<!-- #endif -->
</view>
</template>
<script>
export default {
methods: {
navigateToMiniProgram() {
// 小程序跳转逻辑
uni.navigateTo({
url: '/pages/index/index'
});
},
navigateToWebPage() {
// Web 页面跳转逻辑
window.location.href = 'https://www.example.com';
}
}
};
</script>
* 在这个例子中,`#ifdef MP-WEIXIN` 包裹的代码只会编译到微信小程序中,`#ifdef H5` 包裹的代码只会编译到 Web 页面中。
* 常用的平台标识:
* `H5`: Web 页面
* `MP-WEIXIN`: 微信小程序
* `MP-ALIPAY`: 支付宝小程序
* `MP-BAIDU`: 百度小程序
* `APP-PLUS`: App (原生渲染)
* `APP-PLUS-NVUE`: App (Weex 渲染)
- 平台特有 API:
- UniApp 提供了一套统一的 API,尽量抹平了不同平台的差异。但是,有些平台特有的 API 还是需要单独处理。
- 比如,微信小程序有
wx.getUserInfo
获取用户信息,而 Web 页面可能需要用其他方式实现。 - 咱们可以使用
uni.getSystemInfo
获取平台信息,然后根据平台信息来调用不同的 API。
uni.getSystemInfo({
success: (res) => {
if (res.platform === 'devtools') {
// 开发者工具
} else if (res.platform === 'android') {
// Android
} else if (res.platform === 'ios') {
// iOS
}
}
});
- UI 适配:
- 不同平台的 UI 规范不一样,比如字体大小、颜色、间距等等。UniApp 提供了
uni-app
内置的组件库,这些组件在不同平台上的表现基本一致。 - 当然,如果需要更精细的 UI 控制,可以使用 CSS 样式,并结合条件编译来针对不同平台进行适配。
- 不同平台的 UI 规范不一样,比如字体大小、颜色、间距等等。UniApp 提供了
版本管理:让代码井然有序
版本管理是软件开发中非常重要的一环。UniApp 项目的版本管理主要涉及到以下几个方面:
-
代码版本管理 (Git):
- 这是最基础的版本管理方式。使用 Git 可以跟踪代码的修改历史,方便回滚和协作开发。
- 常用的 Git 命令:
git init
: 初始化 Git 仓库git add .
: 添加所有文件到暂存区git commit -m "提交信息"
: 提交代码git push origin main
: 推送代码到远程仓库 (GitHub, GitLab 等)git pull origin main
: 从远程仓库拉取代码git branch
: 查看分支git checkout -b feature/new-feature
: 创建并切换到新的分支git merge feature/new-feature
: 合并分支
-
应用版本号:
- 每个应用都需要一个版本号,用来区分不同的版本。UniApp 项目的版本号在
manifest.json
文件中配置。
- 每个应用都需要一个版本号,用来区分不同的版本。UniApp 项目的版本号在
{
"versionName": "1.0.0",
"versionCode": "100"
}
* `versionName` 是给用户看的版本号,比如 "1.0.0"。
* `versionCode` 是给程序用的版本号,必须是整数,每次发布新版本都要递增。
* 在 App 中,`versionName` 会显示在应用信息页面,`versionCode` 用于应用升级判断。
* 在小程序中,`versionName` 和 `versionCode` 也会用于版本管理和更新。
-
平台差异化版本管理:
- 有时候,不同的平台需要发布不同的版本,比如 Web 版可能需要修复一个 Bug,而 App 版不需要。
- 这时候,可以利用 Git 的分支管理功能,为每个平台创建一个独立的分支。
- 比如,可以创建
web
分支、app
分支、mp-weixin
分支等等。 - 然后在每个分支上进行相应的修改和发布。
- 这种方式可以保证每个平台的代码都是独立的,不会互相影响。
-
发布流程自动化:
- 手动发布应用非常繁琐,容易出错。可以考虑使用自动化工具来简化发布流程。
- 常用的自动化工具:
- Jenkins: 一个开源的自动化服务器,可以配置各种构建和发布任务。
- Fastlane: 一个专门用于 iOS 和 Android 应用发布的工具,可以自动打包、签名、上传应用。
- GitHub Actions: GitHub 提供的 CI/CD 服务,可以直接在 GitHub 仓库中配置自动化流程。
- 使用自动化工具,可以实现代码提交后自动构建、测试、打包、发布应用,大大提高效率。
UniApp 项目结构:代码复用的基石
一个良好的项目结构是代码复用的基础。UniApp 官方推荐的项目结构如下:
├── components # 公共组件
│ ├── MyButton.vue
│ └── ...
├── pages # 页面
│ ├── index
│ │ ├── index.vue
│ │ └── ...
│ └── ...
├── static # 静态资源
│ ├── images
│ │ ├── logo.png
│ │ └── ...
│ └── ...
├── App.vue # 应用入口
├── main.js # 应用配置
├── manifest.json # 应用清单
├── pages.json # 页面路由配置
└── uni.scss # 全局样式
components
目录存放公共组件,可以在不同的页面中复用。pages
目录存放页面文件,每个页面一个目录。static
目录存放静态资源,比如图片、字体等等。App.vue
是应用的入口组件,类似于 Vue 项目的App.vue
。main.js
是应用的入口文件,用于初始化 Vue 实例、注册全局组件、配置 Vuex 等等。manifest.json
是应用的清单文件,用于配置应用的基本信息,比如应用名称、版本号、图标等等。pages.json
是页面的路由配置文件,用于配置页面的路径、标题、导航栏样式等等。uni.scss
是全局样式文件,可以在这里定义全局的样式变量和样式规则。
实战演练:一个简单的 TodoList 应用
咱们来做一个简单的 TodoList 应用,演示 UniApp 的代码复用和版本管理。
- 创建项目:
- 使用
vue-cli
创建 UniApp 项目:
- 使用
vue create -p dcloudio/uni-preset-5 my-todo-app
* 选择一个模板,比如 "Hello UniApp"。
- 编写代码:
pages/index/index.vue
:
<template>
<view class="container">
<view class="header">
<input type="text" class="input" placeholder="添加任务" v-model="newTask" @confirm="addTask" />
<button class="add-button" @click="addTask">添加</button>
</view>
<view class="list">
<view class="item" v-for="(item, index) in todoList" :key="index">
<checkbox :checked="item.completed" @change="toggleComplete(index)" />
<text class="text" :class="{ completed: item.completed }">{{ item.text }}</text>
<button class="delete-button" @click="deleteTask(index)">删除</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
newTask: '',
todoList: [
{ text: '学习 UniApp', completed: false },
{ text: '完成 TodoList', completed: true }
]
};
},
methods: {
addTask() {
if (this.newTask.trim() === '') {
return;
}
this.todoList.push({ text: this.newTask, completed: false });
this.newTask = '';
},
toggleComplete(index) {
this.todoList[index].completed = !this.todoList[index].completed;
},
deleteTask(index) {
this.todoList.splice(index, 1);
}
}
};
</script>
<style scoped>
.container {
padding: 20px;
}
.header {
display: flex;
margin-bottom: 20px;
}
.input {
flex: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
.add-button {
padding: 10px 20px;
background-color: #409EFF;
color: white;
border: none;
border-radius: 5px;
margin-left: 10px;
cursor: pointer;
}
.list {
border-top: 1px solid #ccc;
padding-top: 20px;
}
.item {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.text {
flex: 1;
margin-left: 10px;
}
.completed {
text-decoration: line-through;
color: #999;
}
.delete-button {
padding: 5px 10px;
background-color: #F56C6C;
color: white;
border: none;
border-radius: 5px;
margin-left: 10px;
cursor: pointer;
}
</style>
- 运行项目:
- 运行到 Web 页面:
npm run dev:h5
* 运行到微信小程序:
npm run dev:mp-weixin
* 运行到 App:
npm run dev:app-plus
* 你会发现,同一份代码,可以在不同的平台上运行,而且 UI 表现基本一致。
- 条件编译:
- 假设需要在微信小程序中添加一个分享按钮:
<template>
<view class="container">
<!-- ... 其他代码 ... -->
<!-- #ifdef MP-WEIXIN -->
<button @click="share">分享</button>
<!-- #endif -->
</view>
</template>
<script>
export default {
// ... 其他代码 ...
methods: {
// ... 其他代码 ...
share() {
// 微信小程序分享逻辑
uni.share({
provider: 'weixin',
type: 0,
success: function (res) {
console.log('share success');
},
fail: function (err) {
console.log('share fail', err);
}
});
}
}
};
</script>
* 这段代码只会编译到微信小程序中,在其他平台上不会显示分享按钮。
- 组件化:
- 将添加任务的输入框和按钮封装成一个组件
AddTask.vue
:
- 将添加任务的输入框和按钮封装成一个组件
<template>
<view class="header">
<input type="text" class="input" placeholder="添加任务" v-model="newTask" @confirm="addTask" />
<button class="add-button" @click="addTask">添加</button>
</view>
</template>
<script>
export default {
data() {
return {
newTask: ''
};
},
methods: {
addTask() {
if (this.newTask.trim() === '') {
return;
}
this.$emit('add', this.newTask); // 触发 add 事件,传递 newTask
this.newTask = '';
}
}
};
</script>
<style scoped>
.header {
display: flex;
margin-bottom: 20px;
}
.input {
flex: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
.add-button {
padding: 10px 20px;
background-color: #409EFF;
color: white;
border: none;
border-radius: 5px;
margin-left: 10px;
cursor: pointer;
}
</style>
* 然后在 `pages/index/index.vue` 中使用该组件:
<template>
<view class="container">
<AddTask @add="addTask" /> <!-- 使用 AddTask 组件 -->
<view class="list">
<view class="item" v-for="(item, index) in todoList" :key="index">
<checkbox :checked="item.completed" @change="toggleComplete(index)" />
<text class="text" :class="{ completed: item.completed }">{{ item.text }}</text>
<button class="delete-button" @click="deleteTask(index)">删除</button>
</view>
</view>
<!-- #ifdef MP-WEIXIN -->
<button @click="share">分享</button>
<!-- #endif -->
</view>
</template>
<script>
import AddTask from '../../components/AddTask.vue'; // 引入 AddTask 组件
export default {
components: {
AddTask // 注册 AddTask 组件
},
data() {
return {
todoList: [
{ text: '学习 UniApp', completed: false },
{ text: '完成 TodoList', completed: true }
]
};
},
methods: {
addTask(newTask) {
// 接收 AddTask 组件传递的 newTask
this.todoList.push({ text: newTask, completed: false });
},
toggleComplete(index) {
this.todoList[index].completed = !this.todoList[index].completed;
},
deleteTask(index) {
this.todoList.splice(index, 1);
},
share() {
// 微信小程序分享逻辑
uni.share({
provider: 'weixin',
type: 0,
success: function (res) {
console.log('share success');
},
fail: function (err) {
console.log('share fail', err);
}
});
}
}
};
</script>
<style scoped>
.container {
padding: 20px;
}
.list {
border-top: 1px solid #ccc;
padding-top: 20px;
}
.item {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.text {
flex: 1;
margin-left: 10px;
}
.completed {
text-decoration: line-through;
color: #999;
}
.delete-button {
padding: 5px 10px;
background-color: #F56C6C;
color: white;
border: none;
border-radius: 5px;
margin-left: 10px;
cursor: pointer;
}
</style>
- 版本管理:
- 将项目初始化为 git 仓库。
- 然后分别创建
web
、mp-weixin
、app
分支,然后根据需要在每个分支上进行修改。 - 修改完成后,合并到主分支。
总结:UniApp 的优势与不足
- 优势:
- 代码复用率高: 一套代码可以编译成多个平台的应用,大大减少了开发成本。
- 学习成本低: 基于 Vue.js,熟悉 Vue.js 的开发者可以快速上手。
- 开发效率高: 丰富的组件库和 API,可以快速构建应用。
- 跨平台能力强: 支持 Web、小程序、App 等多个平台。
- 不足:
- 性能: 在某些场景下,性能可能不如原生应用。
- 平台特性: 有些平台特有的功能可能无法完全支持。
- 生态: 相比原生应用,UniApp 的生态还不够完善。
彩蛋:一些实用技巧
- 使用 HBuilderX 开发: HBuilderX 是 UniApp 官方推荐的开发工具,集成了 UniApp 的各种功能,可以提高开发效率。
- 善用插件市场: UniApp 插件市场有很多第三方插件,可以扩展 UniApp 的功能。
- 多看官方文档: UniApp 官方文档非常详细,包含了各种 API 和组件的用法。
- 多交流学习: 加入 UniApp 的社区,与其他开发者交流学习。
结束语:
UniApp 是一个非常强大的多端应用开发框架,可以帮助咱们快速构建跨平台应用。希望今天的分享对大家有所帮助。记住,代码复用和版本管理是提高开发效率的关键,一定要重视起来! 下课!