瑞吉外卖项目,前端源码(用户端)解析

用户端项目结构,一个典型的移动端外卖应用通常包含这些核心部分:

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. 购物车功能实现

购物车是外卖应用的核心功能之一,我们的实现思路是:

  1. 点击菜品弹出详情对话框
  2. 选择数量后加入购物车
  3. 底部购物车图标实时显示商品数量
  4. 点击购物车展示已选商品列表
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 调用等基础知识,更重要的是学会了如何将这些知识整合起来,开发一个完整的应用。

外卖类应用的核心在于良好的用户体验和流畅的交互,这需要我们在细节上下功夫:按钮的反馈、加载的状态、动画的过渡等等。

相关推荐
天平2 小时前
油猴脚本创建webworker踩坑记录
前端·javascript·typescript
原则猫3 小时前
前端基础大厦
前端
陈随易4 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
SoaringHeart5 小时前
Flutter进阶:基于 EasyRefresh 的下拉刷新封装 n_easy_refresh_mixin.dart
前端·flutter
IT_陈寒7 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰8 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
竹林8188 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花9 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12279 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude
咪库咪库咪10 小时前
Vue3-生命周期
前端