用户端项目结构,一个典型的移动端外卖应用通常包含这些核心部分:
bash
├── api/ # 接口请求模块
├── images/ # 图片资源
├── js/ # 工具脚本
├── page/ # 页面文件
├── styles/ # 样式文件
└── index.html # 首页
这种结构设计遵循了 "功能模块化" 的原则,把不同职责的代码分开管理,方便后期维护。特别是对于团队开发来说,清晰的结构能减少很多沟通成本。
一、核心功能实现详解
1. 接口请求封装
我们在api目录下对所有后端接口进行了封装,以main.js为例:
javascript
//获取所有的菜品分类
function categoryListApi() {
return $axios({
'url': '/category/list',
'method': 'get',
})
}
//获取菜品分类对应的菜品
function dishListApi(data) {
return $axios({
'url': '/dish/list',
'method': 'get',
params:{...data}
})
}
这种做法的好处是:
- 统一管理接口地址,后期接口变更时只需修改一处
- 便于添加请求拦截器和响应拦截器,处理 token 验证、错误提示等共性逻辑
- 页面中调用接口时更加简洁,只需引入对应函数
2. 首页布局与样式设计
首页是用户接触最多的页面,我们在index.html和styles/main.css中做了精心设计:
javascript
<div class="divBody">
<div class="divType">
<ul>
<li v-for="(item,index) in categoryList" :key="index"
@click="categoryClick(index,item.id,item.type)"
:class="{active:activeType === index}">{{item.name}}</li>
</ul>
</div>
<div class="divMenu">
<!-- 菜品列表 -->
</div>
</div>
样式上采用了 rem 单位配合 base.js 的根字体设置,实现了完美的响应式布局:
javascript
#main .divBody .divType ul li {
padding: 16rem;
font-size: 13rem;
color: #666666;
line-height: 18rem;
}
#main .divBody .divType ul li.active {
color: #333333;
font-weight: 500;
background-color: #ffffff;
}
这里的小技巧是:
- 使用 rem 单位实现自适应,1rem=10px 便于计算
- 给活跃状态添加明显的样式区分
- 合理使用 flex 布局实现左右分栏
3. 购物车功能实现
购物车是外卖应用的核心功能之一,我们的实现思路是:
- 点击菜品弹出详情对话框
- 选择数量后加入购物车
- 底部购物车图标实时显示商品数量
- 点击购物车展示已选商品列表
javascript
#main .divCart {
width: 345rem;
height: 44rem;
background: #000000;
border-radius: 25rem;
position: fixed;
left: 50%;
bottom: 24rem;
transform: translate(-50%, 0);
z-index: 3000;
}
交互逻辑上,我们通过 Vue 的数据绑定实现了购物车数据的实时更新:
javascript
// 加入购物车
addCart(item) {
// 检查是否已在购物车
const index = this.cartData.findIndex(cart => cart.id === item.id);
if (index > -1) {
this.cartData[index].number += 1;
} else {
this.cartData.push({...item, number: 1});
}
// 保存到本地存储
localStorage.setItem('cartData', JSON.stringify(this.cartData));
}
4. 订单相关功能
订单模块涉及订单列表、订单详情、再来一单等功能。在order.css中我们定义了订单相关的样式:
javascript
#order .divBody .item .timeStatus {
height: 46rem;
line-height: 20rem;
font-size: 14rem;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2rem dashed #efefef;
border-top: 1px solid #efefef;
}
#order .divBody .btn .btnAgain {
width: 124rem;
height: 36rem;
border: 1px solid #e5e4e4;
border-radius: 19rem;
font-size: 14rem;
text-align: center;
line-height: 36rem;
}
"再来一单" 功能通过调用orderAgainApi接口实现:
javascript
//再来一单
function orderAgainApi(data) {
return $axios({
'url': '/order/again',
'method': 'post',
data
})
}
二、移动端适配技巧
外卖应用主要面向移动端用户,所以适配非常重要。我们项目中采用的适配方案是:
使用 rem 作为单位,通过 js 动态设置根元素 font-size
javascript
// base.js中
(function() {
function setFontSize() {
const html = document.documentElement;
const width = html.clientWidth;
// 以750px设计稿为基准,1rem = 10px
html.style.fontSize = width / 75 + 'px';
}
setFontSize();
window.addEventListener('resize', setFontSize);
})();
关键元素使用固定定位,保证在各种设备上的位置一致
javascript
#main .divCart {
position: fixed;
left: 50%;
bottom: 24rem;
transform: translate(-50%, 0);
}
合理使用 overflow 属性处理内容溢出
javascript
#main .divBody .divMenu .divItem .divName {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
三、性能优化实践
在实际项目中,性能优化是必不可少的环节:
图片懒加载:使用 element-ui 的 el-image 组件实现
javascript
<el-image :src="imgPathConvert(item.image)" >
<div slot="error" class="image-slot">
<img src="./images/noImg.png"/>
</div>
</el-image>
数据缓存:将购物车数据保存到 localStorage,避免页面刷新后数据丢失
合理使用 v-if 和 v-show:对于频繁切换显示状态的元素用 v-show,对于不常切换的用 v-if
减少 DOM 操作:通过 Vue 的数据绑定减少直接操作 DOM 的次数
四、总结
通过这个项目,初学者不仅掌握了 Vue、CSS 布局、API 调用等基础知识,更重要的是学会了如何将这些知识整合起来,开发一个完整的应用。
外卖类应用的核心在于良好的用户体验和流畅的交互,这需要我们在细节上下功夫:按钮的反馈、加载的状态、动画的过渡等等。