小米商城项目解析(完)


一、 项目架构

  1. 封装各个模块的api

在这里插入图片描述
例如:

import request from '@/utils/request'
export default {
    //请求收藏接口
    getCollect(data) {
        return request({
            url: '/api/user/collect/getCollect',
            method: 'post',
            data: data
        })
    },
    //删除收藏
    deleteCollect(data) {
        return request({
            url: '/api/user/collect/deleteCollect',
            method: 'post',
            data: data
        })
    },
}

  1. 整理模块 和命名规范

在这里插入图片描述

在这里插入图片描述

  1. 路由及懒加载
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    // *重定向
    redirect: 'HomePage'
  },
  //* 首页
  {
    path: '/Shoppe',
    name: 'Shoppe',
    component: () => import(/* webpackChunkName: "首页" */ '../views/Shoppe.vue'),
    children: [
      {
        path: '/HomePage',
        name: 'HomePage',
        component: () => import(/* webpackChunkName: "首页" */ '../views/HomePage.vue'),
        
      },
      {
        path: '/goods',
        name: 'goods',
        component: () => import(/* webpackChunkName: "首页" */ '../views/Goods.vue'),

        meta: {
          break: ['全部商品', '分类'],
          keepAlive: true,
        }

      },
      {
        path: '/details',
        name: 'details',
        component: () => import(/* webpackChunkName: "首页" */ '../components/module/Details.vue'),
      },
      {
        path: '/myerror',
        name: 'myerror',
        component: () => import(/* webpackChunkName: "断网" */ '../components/module/myError.vue')
      },
      {
        path: '/collect',
        name: 'Collect',
        component: () => import(/* webpackChunkName: "收藏" */ '../views/Collect.vue')
      },
      {
        path: '/shopping',
        name: 'shopping',
        component: () => import(/* webpackChunkName: "购物车" */ '../views/Shopping.vue')
      },
      {
        path: '/confirmOrder',
        name: 'confirmOrder',
        component: () => import(/* webpackChunkName: "订单" */ '../views/ConfirmOrder.vue')
      },
      {
        path: '/Order',
        name: 'Order',
        component: () => import(/* webpackChunkName: "订单" */ '../views/Order.vue')
      },
    ]
  }
]

二、项目技术栈

  • axios
  • element-ui
  • vuex
  • xuex-persist
  • node-sass
  • vue-cli

三、项目所有模块及技术点

跨域
  • 通过proxy代理解决跨域
module.exports = {
  publicPath: './',
  //*再开开
  devServer: {
    open: true,
    proxy: {
      '/api':{
        target: 'http://39.100.7.70:81/',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}


登录组件
1. 路由鉴权

路由的鉴权,在没有登录的时候跳转购物车,我的收藏时 调用vuex中的方法,弹出登录框

//*路由鉴权
router.beforeEach((to, from, next) => {

  //*判断有没有登录
  if (store.state.token == "") {
    //*去哪些页面
    if (to.path == "/collect" || to.path == "/shopping") {
      //*没有登陆就发送vuex
      store.commit("uplogin")
    }
  }
  next()
})
2.登录校验
 registerLogin: {
        userName: [
          { validator: validateLogin1, required: true, trigger: "blur" },

          {
            pattern: /^[a-zA-Z]([-_a-zA-Z0-9]{5,16})$/,
            message: "字母开头,长度5-16之间,允许字母数字下划线",
          },
        ],
        password: [{ validator: validateLogin2, trigger: "blur" }],
      },

首页
1. 顶部组件

在这里插入图片描述

  • 登录后如果购物车内总条数大于1时,购物车颜色高亮,

  • 登录弹出框需要拆成组件,当没登陆时需要弹出

2. 底部组件

在这里插入图片描述

  • 布局及样式
  • 精灵图使用
.elvesFigure {
      width: 40px;
      height: 40px;
      background: url("../../assets/us-icon.png") no-repeat 0px 0px; /* 第一个图标*/
    }
3. tab栏

在这里插入图片描述

  • 点击进行相应的跳转
<el-menu
              :default-active="activeIndex"
              class="el-menu-demo"
              mode="horizontal"
              active-text-color="red"
              router
            >
              <el-menu-item index="/">首页</el-menu-item>
              <el-menu-item index="goods">全部商品</el-menu-item>
              <el-menu-item index="3">关于我们</el-menu-item>
            </el-menu>
  • 搜索框,路由传参,通过监听$route获取数据
determineSearch() {
      this.$router.push({
        path: `/goods?search=${this.search}`,
      });
    },
$route(val) {
      if (val.query.categoryID) {
        this.categoryID = val.query.categoryID;
        this.getProductByCategory();
        return;
      }
      if (val.query.search) {
        this.search = val.query.search;
        this.getProductBySearch();
      }
    },
4. 轮播图
 <div class="slideshow">
        <el-carousel height="460px">
          <el-carousel-item v-for="(item, index) in carouselData" :key="index">
            <img class="slideshowImg" :src="'api' + item.imgPath" alt="" />
          </el-carousel-item>
        </el-carousel>
      </div>

商品全局组件
  • 相应布局
    在这里插入图片描述
1.注册全局组件

//注册全局组件
import mymodel from './components/module/myModel'
Vue.component(mymodel.name, mymodel)
2.点击更多
BrowseMore() {
      let arr = [];
      this.categoryName.forEach((item) => {
        arr.push(item.category_id);
      });

      function data(arr) {
        return [...new Set(arr)];
      }
      let list = data(arr);

      this.$router.push({
        path: "/goods?categoryID",
        query: { categoryID: list },
      });
    },

全部商品

在这里插入图片描述

1.tabs
<el-tabs v-model="activeName" type="card">
          <el-tab-pane
            v-for="item in tabList"
            :key="item.category_id"
            :label="item.category_name"
            :name="'' + item.category_id"
          ></el-tab-pane>
        </el-tabs>
  • 将全局组件渲染的数组 换成全部商品里的数据
<mymodel
        style="lll"
        :sTyle="{ width: '19%' }"
        :categoryName="AllProduct"
        :flags="false"
      ></mymodel>
2.分页
<el-pagination
          @current-change="currentChange"
          :page-size="pageSize"
          background
          layout="prev, pager, next"
          :total="total"
        >
        </el-pagination>
  • 切换分页
currentChange(currentPage) {
      this.currentPage = currentPage;
    },

详情
  • 基本布局

在这里插入图片描述

1.加入购物车
  • 加入购物车需要判断用户有无登录token,如果没有需要 弹出登录框
//*加入购物车判断
    async addShopping() {
      if (this.$store.state.token == "") {
        //*发送参数,显示弹框
        this.$store.commit("uplogin");
      } else {
        //*请求数据
        let { data: item } = await ShoppingApi.addShoppingCart({
          user_id: this.$store.state.userId,
          product_id: this.DetailsData.product_id,
        });
        this.$notify({
          title: "成功",
          message: item.msg,
          type: "success",
        });
      }
    },
2. 添加收藏
  • 思路同上,判断有无登录
//*添加收藏
    async fond() {
      if (this.$store.state.token == "") {
        this.$store.commit("uplogin");
      } else {
        let { data: item } = await DetailsApi.addCollect({
          user_id: this.$store.state.userId,
          product_id: this.DetailsData.product_id,
        });
        // 添加收藏成功
        if (item.code == "001") {
          this.$notify({
            title: "成功",
            message: "添加收藏成功",
            type: "success",
          });
        } else {
          this.$notify.error({
            title: "错误",
            message: item.msg,
          });
        }
      }
    },

购物车
  • 购物车为空时
    在这里插入图片描述
  • 购物车总条数 > 1
    在这里插入图片描述
1.全选
  • elementui 自带全选反选,只需将选中的数据发送到vuex中
//*点击单选全选,发送数据到vuex,计算
    handleSelectionChange(val) {
      this.multipleSelection = val;
      if (val.length > 0) {
        this.flag = true;
      } else {
        this.flag = false;
      }
      this.$store.commit("handleSelectionChange", val);
    },
2.删除
  • 删除选中的购物车数据
// *删除
    async deleteShoppingCart(data) {
      let { data: item } = await shoppingApi.deleteShoppingCart({
        user_id: this.$store.state.userId,
        product_id: data.productID,
      });
      if (item.code == "001") {
        //   删除购物车成功
        this.$notify({
          title: "成功",
          message: item.msg,
          type: "success",
        });
        this.getShoppingCart();
      }
    },
3.总价格和总数量
  • 计算属性
getters: {
    //*总价格
    totals(state) {
      let amounts = 0
      state.handleSelectionChange.forEach(item => {
        amounts += item.price * item.num
      })
      return amounts
    },
    //*总个数
    totalQuantity(state) {
      let amounts = 0
      state.handleSelectionChange.forEach(item => {
        amounts += item.num
      })
      return amounts
    },
    
  },

  • 在页面中调用计算属性
<span>{{this.$store.getters.totalQuantity}}</span>

我的订单
  • 渲染
    在这里插入图片描述

我的收藏
  • 更换全局组件数据

在这里插入图片描述

  • 替换全局组件数据

 <mymodel
        style="margin-top: 18px"
        @collectList="collectList"
        :CloseHide="true"
        :sTyle="{ width: '19%' }"
        :categoryName="collectionData"
        :flags="false"
      ></mymodel>

确认订单
  • 数据渲染
    在这里插入图片描述
  • 结算成功后跳转我的订单
async addOrder() {
      let { data: item } = await comfirmorderApi.addOrder({
        products: this.multipleSelection,
        user_id: this.$store.state.userId,
      });
      if (item.code == "001") {
        this.$notify({
          title: "成功",
          message: item.msg,
          type: "success",
        });
        this.$router.push({
          path: `/Order`,
        });
      }
    },

  • 3
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值