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

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

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 调用等基础知识,更重要的是学会了如何将这些知识整合起来,开发一个完整的应用。

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

相关推荐
用户93051065822242 小时前
module federation,monorepo分不清楚?
前端·架构
柳安2 小时前
手写new操作符执行过程
前端·javascript
狗哥哥2 小时前
Vue 3 统一面包屑导航系统:从配置地狱到单一数据源
前端·vue.js·架构
可乐红烧西红柿3 小时前
tauri2+vue+vite实现基于webview视图渲染的桌面端开发
前端·前端框架
鱼鱼块3 小时前
从后端拼模板到 Vue 响应式:前端界面的三次进化
前端·vue.js·面试
UIUV3 小时前
JavaScript内存管理与闭包原理:从底层到实践的全面解析
前端·javascript·代码规范
无限大63 小时前
为什么计算机要使用二进制?——从算盘到晶体管的数字革命
前端·后端·架构
良木林3 小时前
字节前端高频面试题试析
前端
一 乐3 小时前
家政管理|基于SprinBoot+vue的家政服务管理平台(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot