Uniapp+Vue3旅游小程序项目实战|个人完整学习总结

Uniapp+Vue3旅游小程序项目实战|个人完整学习总结 本文结合完整旅游App实战项目汇总Uniapp通用基础知识点、开发环境配置、项目搭建、接口封装、页面开发、多端适配全套内容零基础可直接上手适配微信小程序、H5、App多端开发完整复刻实战项目开发流程。项目实战视频来源https://www.bilibili.com/video/BV1zA9ZYvE1e?p22vd_source2a6f44e5bd6407acc4cc2bc1d135ccbc第一部分Uniapp 通用基础知识1.1 页面三层结构每个.vue页面固定三段Uniapp 所有页面文件统一分为视图层 template、逻辑层 script、样式层 style项目全程采用 Vue3 组合式 setup 写法摒弃 Vue2 繁琐的配置式写法代码更简洁高效。完整标准页面模板!-- 1.视图层写页面上能看到的所有内容等同于HTML -- template !-- uni不能用div、span、p等html标签必须用小程序规范标签 -- view classbox !-- view div 块级容器 -- text{{ msg }}/text !-- text span 文字标签文字必须包在text里 -- /view /template !-- 2.逻辑层处理数据、接口、点击事件所有JS代码放这里 -- script setup // Vue3组合式API不用写export default直接定义变量方法 import { ref } from vue // ref定义响应式文本/数字变量页面直接插值使用 const msg ref(巩固uni-app基础) /script !-- 3.样式层控制页面颜色、宽高、边距 -- style langscss scoped /* langscss 开启scss语法支持变量、嵌套样式 */ /* scoped样式只作用于当前页面不会污染其他页面 */ .box { padding: 20rpx; } /style核心注意事项template 根标签只能有一个所有页面内容必须包裹在同一个根view中禁止使用 div、span、img 等HTML原生标签统一替换为 view、text、image所有文字内容必须写在 text 标签内否则小程序会出现文字排版错乱、兼容问题。1.2 rpx适配、全局uni.scss、条件编译1rpx 自适应单位多屏幕适配核心为解决手机屏幕尺寸、分辨率差异问题Uniapp 专属自适应单位 rpx是跨端适配的核心方案。统一规则750rpx 设备完整屏幕宽度行业统一750px设计稿标准使用方式设计图标注多少px代码直接写多少rpx例30px字体→30rpx350px宽度→350rpx底层自动换算大屏自动放大、小屏自动缩小全设备展示比例完全一致对比pxpx为固定像素大屏显示过小、小屏内容挤压Uniapp开发优先全部使用rpx。2全局样式 uni.scss普通scss文件需要每个页面手动import导入冗余繁琐而 uni.scss 是Uniapp项目专属全局样式文件框架会自动注入到每一个页面、组件的style中无需手动引入全局生效。UI组件库适配规则若项目使用 uview-plus、uni-ui 等组件库必须在 uni.scss 第一行引入组件库主题样式后续自定义变量才能覆盖组件库默认配色。// 使用uview-plus必加必须置于uni.scss第一行 import/uni_modules/uview-plus/theme.scss;3条件编译一套代码兼容多端Uniapp一套代码可打包微信小程序、H5、App安卓/iOS但部分API、样式、语法多端不通用通过条件编译区分端逻辑打包时自动删除无关代码实现多端兼容。基础语法规则//#ifdef 端标识仅当前端生效if 如果//#ifndef 端标识非当前端生效if not 非//#endif条件结束标记必须成对使用不可遗漏常用端标识及场景#ifdef MP-WEIXIN仅微信小程序微信登录、小程序分享#ifdef H5仅网页浏览器鼠标样式、网页专属路由#ifdef APP-PLUS仅手机App原生推送、本地文件操作#ifndef APP-PLUS除App外所有端H5小程序屏蔽App不兼容接口#ifdef VUE3仅Vue3项目生效Vue2/Vue3兼容示例// 当前是vue3项目才执行 //#ifdef VUE3 import { createSSRApp } from vue // #endif // 不是vue3vue2才执行 //#ifndef VUE3 import Vue from vue //#endif1.3 常用指令页面数据绑定核心所有指令均书写在 template 标签中用于快速实现页面数据渲染、交互绑定v-for(item,index) in 列表循环渲染列表商品、菜单、景点列表使用时必须绑定keyv-if布尔值条件渲染满足条件渲染标签不满足则直接移除DOMv-bind:属性变量动态绑定标签属性简写:属性变量图片地址、动态classv-on:事件方法绑定交互事件简写事件方法click点击事件v-model变量表单双向绑定输入框内容自动同步JS变量数据。1.4 页面生命周期页面级生命周期script setup 中使用生命周期触发时机使用场景onLoad页面加载仅执行一次页面初始化接口请求、接收路由参数onReachBottom页面滚动触底分页加载更多列表数据onPageScroll页面滚动实时触发滚动修改导航栏样式、显示/隐藏悬浮按钮App全局生命周期App.vue中使用执行顺序onLaunch → onShow → onHideonLaunch程序首次打开仅执行1次用于项目初始化、设备信息获取、全局登录校验onShow页面/应用显示时触发onHide页面/应用切后台隐藏时触发。1.5 路由跳转与页面传参1四种核心跳转API区别uni.navigateTo()普通页面跳转保留上一页自带返回箭头不可跳转tabBar页面uni.navigateTo({url:/pages/goods/goods})uni.switchTab()专门用于切换底部tabBar页面跳转后销毁所有非tab页面uni.switchTab({url:/pages/mine/mine})uni.redirectTo()跳转并关闭当前页面无法返回上一页适用于登录成功后跳转首页uni.redirectTo({url:/pages/index/index})uni.navigateBack()返回上N级页面无参数默认返回上一页delta指定返回层级uni.navigateBack() // 返回上一页uni.navigateBack({delta:2}) // 一次性退回2页A→B→CC直接返回A2两种页面传参方式① 普通字符串传参数字、短文本// 跳转页面携带id参数 uni.navigateTo({ url: /pages/detail/detail?id1001 }) // 接收页onLoad(options){ console.log(options.id) }② 复杂对象/数组传参序列化转码对象直接拼接URL会丢失数据需通过JSON.stringify encodeURIComponent转义接收端反向解析const info { name:张三,age:18 } uni.navigateTo({ url: /pages/detail/detail?data${encodeURIComponent(JSON.stringify(info))} }) // 接收页面解析 onLoad((options){ const obj JSON.parse(decodeURIComponent(options.data)) })1.6 常用内置uni APIuni.showToast轻提示弹窗成功/失败文字提示2秒自动消失uni.showModal确认弹窗自带取消/确定按钮用于二次确认操作uni.showLoading加载动画接口请求时开启必须搭配 uni.hideLoading() 关闭uni.setStorageSync/uni.getStorageSync同步本地缓存存储/读取数据存token、用户信息uni.login微信小程序授权登录获取临时code用于后端登录校验。1.7 组件基础1. easycom自动引入机制配置easycom后页面使用自定义组件/UI库组件无需手动import导入、无需注册直接书写标签即可使用极大简化开发。2. 父子组件通信父传子自定义属性绑定 Child :namename/子组件通过 defineProps 接收子传父子组件自定义$emit事件派发父组件通过事件监听接收v-model双向绑定语法糖简化父子传值实现数据双向同步。第二部分Uniapp 开发环境安装与配置2.1 HBuilderX安装与常用插件官网下载HBuilderX 标准版即可满足开发需求必备插件工具 → 插件安装uni-app 编译器核心插件新建项目自动安装scss/sass 编译支持scss样式语法uni-app 真机运行微信小程序真机调试必备。编辑器配置工具 → 设置 → 编辑器配置可自定义字体、字号、自动保存、缩进等。2.2 新建Uniapp项目文件 → 新建 → 项目 → 选择 uni-app自定义项目名称、存储路径模板选择Vue3版本本项目全程使用Vue3组合式语法创建完成后自动生成项目基础目录结构。2.3 运行调试方式运行方式操作路径说明浏览器运行运行 → 运行到浏览器H5端开发调试支持热更新实时预览微信小程序模拟器运行 → 运行到小程序模拟器 → 微信开发者工具需提前配置开发者工具路径微信真机调试微信开发者工具 → 预览/真机调试手机扫码真机查看适配效果2.4 微信开发者工具关联配置下载安装微信开发者工具HBuilderX配置路径工具 → 设置 → 运行配置 → 填写微信开发者工具安装路径开发者工具开启服务端口设置 → 安全设置 → 开启服务端口关闭域名校验开发必备项目详情 → 本地设置 → 勾选「不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书」。2.5 项目引入UI组件库uview-plus本项目采用 Vue3 专属的uview-plus组件库搭配uni-ui实现完整UI布局安装配置步骤HBuilderX插件市场搜索uview-plus直接导入插件到项目插件自动安装至 uni_modules/uview-plus/ 目录main.js 全局注册组件库import uviewPlus from ./uni_modules/uview-plus // Vue3 部分 import { createSSRApp } from vue export function createApp() { const app createSSRApp(App) app.use(uviewPlus) // 注册 uview-plus return { app } }uni.scss 引入主题变量置于第一行import /uni_modules/uview-plus/theme.scss;pages.json 配置easycom自动引入easycom: { autoscan: true, custom: { ^u--(.*): /uni_modules/uview-plus/components/u-$1/u-$1.vue, ^up-(.*): /uni_modules/uview-plus/components/u-$1/u-$1.vue, ^u-([^-].*): /uni_modules/uview-plus/components/u-$1/u-$1.vue } }配置完成后所有uview-plus组件up-swiper、up-button等无需手动导入直接使用标签即可。同时项目引入uni-ui组件库图标、列表等同样通过插件市场导入easycom自动识别。2.6 核心配置文件基础认识1. pages.json页面路由与全局样式配置核心作用注册页面路由、配置tabBar、全局导航栏样式、组件自动引入规则{ pages: [ { path: pages/index/index, style: { navigationBarTitleText: uni-app } }, { path: pages/detail/detail, style: { navigationStyle: custom } } ], tabBar: { list: [ { pagePath: pages/index/index, text: 首页 }, { pagePath: pages/like/like, text: 喜欢 }, { pagePath: pages/my/my, text: 我的 } ] }, globalStyle: { navigationBarTextStyle: black, navigationBarBackgroundColor: #F8F8F8 } }2. manifest.json应用全局配置核心配置项name应用名称appid项目唯一标识mp-weixin微信小程序专属配置appid、域名校验等vueVersion指定Vue版本本项目为3。第三部分旅游App实战项目开发流程本项目为零基础入门练手项目结构清晰、功能完整主打熟悉UniappVue3开发语法、接口请求、多端适配、页面交互逻辑适合新手实战练手。3.1 项目整体结构与页面规划项目目录结构旅游uniapp/ ├── api/ # 接口层 │ ├── api.js # 接口地址定义 │ ├── http.js # 请求封装 │ ├── mock.js # Mock 拦截入口 │ └── mockData/ │ └── pageApi.js # Mock 数据 ├── pages/ # 页面 │ ├── index/index.vue # 首页轮播图瀑布流 │ ├── detail/detail.vue # 详情页 │ ├── line/line.vue # 游玩线路页地图推荐 │ ├── like/like.vue # 喜欢页 │ └── my/my.vue # 我的页登录个人信息 ├── static/ # 静态资源 │ └── tabbar/ # tabBar 图标 ├── uni_modules/ # 插件目录uview-plus 等 ├── App.vue # 应用入口 ├── main.js # 主入口 ├── pages.json # 路由与全局配置 ├── manifest.json # 应用配置 ├── uni.scss # 全局样式变量 └── package.json # 依赖管理页面功能规划页面路径页面类型核心功能首页pages/index/indextabBar主页面搜索、轮播图、景点瀑布流列表、触底加载喜欢页pages/like/liketabBar主页面收藏景点卡片列表展示我的页pages/my/mytabBar主页面微信授权登录、用户信息展示、功能列表详情页pages/detail/detail普通跳转页景点详情、游玩推荐、跳转线路页线路页pages/line/line普通跳转页地图定位、景点评分、横向推荐列表tabBar完整配置{ pages: [ { path: pages/index/index, style: { navigationBarTitleText: uni-app } }, { path: pages/like/like, style: { navigationBarTitleText: } }, { path: pages/my/my, style: { navigationBarTitleText: } }, { path: pages/detail/detail, style: { navigationBarTitleText: , navigationStyle: custom } }, { path: pages/line/line, style: { navigationBarTitleText: } } ], tabBar: { color: #7A7E83, selectedColor: #2867CE, list: [ { pagePath: pages/index/index, iconPath: static/tabbar/ly-home01.png, selectedIconPath: static/tabbar/ly-home.png, text: 首页 }, { pagePath: pages/like/like, iconPath: static/tabbar/ly-link01.png, selectedIconPath: static/tabbar/ly-link.png, text: 喜欢 }, { pagePath: pages/my/my, iconPath: static/tabbar/ly-my01.png, selectedIconPath: static/tabbar/ly-my.png, text: 我的 } ] } }3.2 项目全局样式与UI组件全局引入uni.scss 全局样式配置仅存放全局scss变量不写具体样式避免全局注入冗余代码、增大包体积import /uni_modules/uview-plus/theme.scss;main.js 全局注册配置全局注册UI组件库、引入Mock模拟数据import App from ./App import uviewPlus from ./uni_modules/uview-plus import ./api/mock.js // 引入 Mock 数据拦截 // Vue3 import { createSSRApp } from vue export function createApp() { const app createSSRApp(App) app.use(uviewPlus) // 全局注册 uview-plus return { app } }pages.json easycom配置配置后所有uview-plus组件无需手动导入直接使用标签开发easycom: { autoscan: true, custom: { ^u--(.*): /uni_modules/uview-plus/components/u-$1/u-$1.vue, ^up-(.*): /uni_modules/uview-plus/components/u-$1/u-$1.vue, ^u-([^-].*): /uni_modules/uview-plus/components/u-$1/u-$1.vue } },3.3 网络请求写法与数据请求调用1. 全局请求封装api/http.js基于Promise封装uni.request统一处理请求头、响应拦截、错误提示支持async/awaitlet baseUrl // 通过环境判断接口地址 if (process.env.NODE_ENV development) { baseUrl https://m1.apifoxmock.com/m1/4728220-0-default/api } else { baseUrl https://m1.apifoxmock.com/m1/4728220-0-default/api } 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) || // 自动携带 token }, success: res { if (res.statusCode 200) { if (res.data.code 1) { resolve(res.data.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 }) } }) }) }2. 接口统一管理api/api.js所有接口统一封装便于维护和修改import http from ./http.js export const getBanner () { return http(/user/getBanner) } export const getHomeList () { return http(/user/getHomeList) } export const login (code) { return http(/login, { code }, POST) } export const getUserInfo () { return http(/getUserInfo) } export const detailProject () { return http(/detail/project) } export const projectInfo (id) { return http(/project/info, id) } export const likeList () { return http(/like/list) }3. 页面接口调用实战所有页面数据请求统一在 onLoad 生命周期中执行// 首页 — 加载轮播图和列表 onLoad(() { getBanner().then(res { bannerList.value res.bannerList }) getHomeList().then(res { flowList.value res }) }) // 喜欢页 onLoad(() { likeList().then(res { linkList.value res }) }) // 详情页 — 加载游玩项目推荐 onLoad((opt) { detailProject().then(res { projectList.value res }) details.dt JSON.parse(decodeURIComponent(opt.item)) }) // 线路页 — 通过 id 请求项目详情 onLoad((props) { projectInfo({ id: props.id }).then(res { detailInfo.value res }) }) // 我的页 — 登录后获取用户信息 uni.login({ success: async (data) { const { token } await login(data.code) uni.setStorageSync(token, token) const { avatarUrl, nickName } await getUserInfo() } })4. Mock数据模拟开发调试开发阶段通过Mock.js拦截接口请求返回模拟数据无需后端接口即可调试页面api/mock.js拦截配置// api/mock.js import Mock from mockjs import pageApi from ./mockData/pageApi Mock.mock(/api\/user\/getBanner/, get, pageApi.getBanner)api/mockData/pageApi.js模拟数据// api/mockData/pageApi.js — 返回模拟的轮播图和列表数据 export default { getBanner: () { return { code: 1, data: { bannerList: [...] }, msg: } }, getHomeList: () { return { code: 1, data: [...], msg: } } }3.4 页面跳转与传参实战1. 首页→详情页复杂对象传参// 发送方将对象序列化后 encodeURIComponent const goDetail (item) { const can JSON.stringify(item) uni.navigateTo({ url: /pages/detail/detail?item${encodeURIComponent(can)} }) } // 接收方反序列化 decodeURIComponent onLoad((opt) { details.dt JSON.parse(decodeURIComponent(opt.item)) })核心原因URL不支持{}、等特殊字符必须通过转义工具处理避免数据丢失、解析异常。2. 详情页→线路页简单ID传参// 发送方 const goLine (item) { uni.navigateTo({ url: /pages/line/line?id${item.id} }) } // 接收方 onLoad((props) { projectInfo({ id: props.id }).then(res { detailInfo.value res }) })3.5 各页面布局与交互实现思路1. 首页搜索轮播瀑布流列表核心功能搜索框、轮播图、公告栏、瀑布流景点列表、触底加载、回到顶部template !-- 搜索栏 -- up-search placeholder搜索景点 v-modelkeyword / !-- 轮播图 -- up-swiper keyNameimage showTitle :listbannerList :autoplaytrue height160 / !-- 公告栏 -- up-notice-bar text项目数据仅为示例非真实数据 / !-- 瀑布流列表 -- up-waterfall v-modelflowList refuWaterfallRef template v-slot:left{ leftList } view v-for(item, index) in leftList :keyindex clickgoDetail(item) up-lazy-load :imageitem.img / view{{ item.title }}/view view{{ item.times }}/view view classdemo-tag view{{ item.tag[0] }}/view view{{ item.tag[1] }}/view /view view v-ifitem.isDot{{ item.isDot }}/view /view /template template v-slot:right{ rightList } !-- 同 left 结构 -- /template /up-waterfall !-- 回到顶部按钮 -- view v-ifshowTopBtn clickTotop up-icon namearrow-upward / /view /template核心交互onReachBottom触底加载更多、onPageScroll监听滚动显示/隐藏回到顶部按钮、图片懒加载优化性能。2. 线路页地图评分横向滚动!-- 地图组件 -- map v-ifdetailInfo.id :markersdetailInfo.markers :latitudedetailInfo.location[0] :longitudedetailInfo.location[1] :show-scaletrue / !-- 评分 -- up-rate :countcount v-modeldetailInfo.count active-color#f56c6c / !-- 横向滚动推荐 -- up-scroll-list :indicatortrue view v-for(item, index) in detailInfo.other image :srcitem.url / view{{ item.name }}/view /view /up-scroll-list3. 喜欢页两列卡片列表view classtj-list view classitem v-for(item, index) in linkList :keyindex image :srcitem.img modeaspectFill / view classtopFixed喜欢/view view classtit{{ item.title }}/view text classtext{{ item.introduce }}/text /view /view核心样式flex两列自适应布局文字超出两行省略优化页面展示效果。4. 我的页登录弹窗用户信息!-- 顶部弧形背景 用户信息卡 -- view classtopBox view classusers clicksetFun template v-if!userInfo.nickName image src../../static/tt.jpg / view注册/登录/view /template template v-else image :srcuserInfo.avatarUrl / view{{ userInfo.nickName }}/view /template /view /view !-- 功能列表 -- uni-list uni-list-item :show-extra-icontrue :extra-iconextraIcon1 showArrow title个人信息 / uni-list-item :show-extra-icontrue :extra-iconextraIcon2 showArrow title我的购物车 / /uni-list !-- 登录弹窗 -- up-popup :showshow closeclose view classpopup view获取您的头像和昵称/view Button open-typechooseAvatar chooseavataronChooseavatar img :srcuserInfo.avatarUrl / /Button input inputchangName typenickname / button clickuserSubmit确定/button /view /up-popup核心逻辑微信授权登录、头像昵称获取、弹窗自定义编辑用户信息、本地缓存存储登录状态。3.6 完整项目开发流程总结整套旅游小程序项目标准化开发流程新手可直接复用需求分析确定5个核心页面及对应功能梳理页面跳转逻辑项目搭建HBuilderX新建Vue3版本Uniapp项目配置pages.json路由、tabBar导航UI环境搭建导入uview-plus、uni-ui组件库配置easycom自动引入、全局样式网络层封装全局http请求封装、统一接口管理、Mock模拟数据配置逐页功能开发依次开发首页、详情页、线路页、喜欢页、我的页完成布局、接口、交互联调测试浏览器、小程序模拟器调试打印日志排查接口、渲染问题Bug修复适配多端样式、接口异常、传参报错等问题多端验证完成H5、微信小程序、App多端适配验证。本总结仅为个人学习复盘仅供自身学习存档和新手参考若内容存在错误、不合理或可优化的地方恳请各位大佬、前辈多多指正我会及时修正、查漏补缺持续精进自身的开发能力