Travel uni-app 项目说明
Github:https://github.com/Young-opener/Travel-uniapp.git
Travel uni-app 项目说明
1. 项目概览
- 跨端旅游类应用,覆盖小程序 / H5 / App。
- 基于 uni-app + Vue 3(兼容 Vue 2)。
- 提供景点浏览、详情推荐、收藏管理、用户中心、路线导航等功能。
- 适合作为旅游行业模板或 uni-app 实战案例。
2. 技术选型
- 框架:uni-app,统一开发多端应用。
- 前端框架:Vue 3 + Composition API,条件编译保留 Vue 2 入口。
- UI:uview-plus 组件库 + easycom 自动导入。
- 样式:SCSS,组件内局部样式隔离。
- 网络:二次封装
uni.request,Promise 化返回值。 - Mock:MockJS(
api/mock.js),开发阶段模拟后端数据。
3. 构建入口
main.js使用条件编译区分 Vue 2 / Vue 3:- Vue 2:
Vue实例 +App.mpType。 - Vue 3:
createSSRApp+app.use(uviewPlus)。
- Vue 2:
- 保证老项目兼容,同时支持最新 Composition API。
4. 页面路由
pages.json配置启动页pages/index/index。- TabBar:
首页、喜欢、我的。 - 其他页面:
detail(景点详情)、line(路线推荐)。 - easycom 映射 uview-plus 组件前缀。
5. 首页(pages/index/index.vue)
- 组件组合:
up-search、up-swiper、up-notice-bar、up-waterfall。 - 瀑布流:左右列 slot,自定义卡片内容。
- 懒加载:
up-lazy-load,避免首屏图片压力。 - 触底加载:
onReachBottom中调用addRandomData模拟分页。 - 滚动监听:
onPageScroll控制返回顶部按钮。 - 详情跳转:JSON 序列化 +
encodeURIComponent保证安全。
6. 详情页(pages/detail/detail.vue)
- 自定义透明导航栏 + 大图背景。
- 景区介绍、开放时间、推荐项目卡片。
- 推荐部分点击跳转到
line页面。 - 页面入口
onLoad解码首页传来的景点信息。
7. 喜欢页(pages/like/like.vue)
- 双列瀑布卡片布局。
- 文案两行省略:
-webkit-line-clamp+line-clamp。 - 页面加载时请求
likeList模拟收藏数据。
8. 我的页(pages/my/my.vue)
- 顶部身份展示 + 功能快捷入口列表。
- 登录流程:
uni.login获取 code。- 调用
login接口换 token。 - 根据 token 拉取
getUserInfo。 - 信息与 token 写入本地缓存。
- 免登录逻辑:
onLoad读取本地缓存自动填充。 - 弹窗获取头像昵称:
chooseAvatar、type="nickname"。
9. 路线页(pages/line/line.vue)
- 原生
map组件显示定位与标记。 up-rate星级评分。up-scroll-list横向推荐其他项目。onLoad根据 id 拉取projectInfo。
10. 数据接口(api/api.js)
- 统一出口:
getBanner、getHomeList、login、getUserInfo、detailProject、projectInfo、likeList。 - 所有接口均依赖封装的
http方法。
11. 网络层(api/http.js)
- 环境区分:开发、生产共用 Apifox Mock 地址(可扩展本地接口)。
- 请求封装:Promise 包裹
uni.request。 - Token 自动携带:header 中读取本地存储。
- 业务码处理:
code == 1成功返回,code == 0Toast 错误。 - 异常兜底:请求失败统一提示“服务器请求异常”。
12. 模拟数据(api/mock.js)
- 引入 MockJS。
- 注册
/api/user/getBanner等模拟接口。 - 便于前后端并行开发。
13. manifest.json 配置
app-plus:应用 splash、权限、模块配置。- 各端
mp-*:微信、支付宝、百度、头条小程序配置。 vueVersion指定为 3。appid仍为空,需上线前填入实际小程序 ID。
14. 性能优化点
- 图片懒加载减少首屏压力。
- 瀑布流左右列错列渲染提升可读性。
- 滚动阈值控制返回顶部按钮,减少 DOM 频繁操作。
- 二次封装请求避免重复创建实例。
- Mock 数据仅开发可用,上线前可移除减少包体。
15. 代码规范与质量
- Composition API 组织逻辑,搭配
<script setup>简化代码。 - Lint 警告修复:CSS 属性补全、移除未使用变量。
- 列表
v-for推荐使用稳定主键(后续可调整)。 uniAPI 封装为独立函数,便于复用与测试。
16. 可扩展建议
- 根据实际后端替换 Mock 地址与接口参数。
- 引入 Pinia/Vuex 管理全局状态(如用户、收藏)。
- 构建环境中按需加载 Mock,避免生产警告。
- 调整
:key为item.id,减少渲染复用问题。 - 引入 CI/CD 打包脚本,实现一键发布。
17. 适用场景
- 旅游攻略类小程序 / App。
- uni-app 与 Vue 3 结合的教学示例。
- 界面展示型产品(美食、资讯、社区)可快速二次开发。
18. 如何运行
- 推荐使用 HBuilderX 打开并运行至目标平台。
- 或使用 CLI:
npm install->npm run dev:%PLATFORM%(需自行补充脚本)。 - 微信小程序端需在开发者工具中编译预览。
19. 注意事项
appid必须在上线前填入真实值。- MockJS 内部使用
eval,仅用于开发调试,不建议打包到生产。 - 小程序登录流程需配套真实后端接口。
- 地图组件在微信、H5 端表现不同,需针对性测试。
20. 总结
- 架构清晰:入口、路由、接口、组件划分合理。
- 体验良好:瀑布流、懒加载、地图、评分等细节完备。
- 工程化:网络层、Mock、条件编译提升维护与扩展能力。
- 适合作为旅游行业模板或 uni-app 技术实践展示。
21. 核心代码片段
- 首页逻辑(瀑布流 + 无限滚动):
<script setup>import { getBanner, getHomeList } from '../../api/api.js'import { onLoad, onReachBottom, onPageScroll } from '@dcloudio/uni-app'import { ref, reactive } from 'vue'const keyword = ref('')const bannerList = ref([])const flowList = ref([])const showTopBtn = ref(0)onLoad(() => {getBanner().then(res => {bannerList.value = res.bannerList})getHomeList().then(res => {flowList.value = res})})onReachBottom(() => {setTimeout(() => {addRandomData()}, 1000)})onPageScroll((e) => {showTopBtn.value = e.scrollTop > 600 ? 1 : 0})const goDetail = (item) => {const can = JSON.stringify(item)uni.navigateTo({url: `/pages/detail/detail?item=${encodeURIComponent(can)}`})}const Totop = () => {uni.pageScrollTo({scrollTop: 0,duration: 300})}const addRandomData = () => {for (let i = 0; i < 10; i++) {let index = uni.$u.random(0, flowList.value.length - 1)let item = JSON.parse(JSON.stringify(flowList.value[index]))item.id = uni.$u.guid()flowList.value.push(item)}}
</script>
- 网络请求封装(自动携带 token + 统一异常):
export default function http(url, data = {}, method = 'GET') {return new Promise((resolve, reject) => {uni.request({url: baseUrl + url,data,method,header: {'token': uni.getStorageSync('token') || ''},success: res => {if (res.statusCode == 200) {if (res.data.code == 1) {resolve(res.data.data)} else if (res.data.code == 0) {uni.showToast({title: res.data.msg,icon: 'none'})reject(res.data.msg)}}},fail: () => {uni.showToast({title: '服务器请求异常',icon: 'none'})}})})
}
- 详情页参数解析与推荐列表:
<script setup>import { onLoad } from '@dcloudio/uni-app'import { ref, reactive } from 'vue'import { detailProject } from '../../api/api.js'const details = reactive({dt: ''})const projectList = ref([])const goLine = (item) => {uni.navigateTo({url: `/pages/line/line?id=${item.id}`})}onLoad((opt) => {detailProject().then(res => {projectList.value = res})details.dt = JSON.parse(decodeURIComponent(opt.item))})
</script>
