从零开始,搭建一个简单的购物平台(十三)前端商城部分

本文最后更新于:9 个月前

从零开始,搭建一个简单的购物平台(十二)前端商城部分
https://blog.csdn.net/time_____/article/details/108471436
项目源码(持续更新):https://gitee.com/DieHunter/myCode/tree/master/shopping

这篇文章我们来实现一下前端商城的工具类,其他配置和全局状态

工具类:

  • 工具类我们统一放在utils文件夹下,并部署在Vue原型上(与Axios的一样)

  • 首先我们要实现两个对象深复制的方法,之前博客也有介绍到,后续对全局静态变量做操作时,只能将其定义为只读,也就是不能改变他的值,所以深复制是很有必要的,对于简单的数据用json方式即可,遇上含有function,set,get等属性时需要用到递归版。

  • JSON:*

    export default class Clone {
      static shallowClone(org) {
        return JSON.parse(JSON.stringify(org));
      }
    }

    递归:

export default class Clone {
  static deepClone(org, tag) {
    var tag = tag || {};
    var name = Object.getOwnPropertyNames(org);
    for (var i = 0; i < name.length; i++) {
      var desc = Object.getOwnPropertyDescriptor(org, name[i]);
      if (typeof desc.value === "object" && desc.value !== null) {
        var obj = desc.value.toString() === "[object Object]" ? {} : [];
        Object.defineProperty(tag, name[i], {
          configurable: desc.configurable,
          enumerable: desc.enumerable,
          writable: desc.writable,
          value: obj
        });
        Clone.deepClone(desc.value, obj);
      } else {
        Object.defineProperty(tag, name[i], desc);
      }
    }
    return tag;
  }
}
  • 本地缓存的封装
import Vue from "vue";
class Storage {
  static saveStorage(key, val) {
    localStorage.setItem(key, JSON.stringify(val));
  }
  static getStorage(key) {
    try {
      return JSON.parse(localStorage.getItem(key)) || [];
    } catch (error) {}
  }
  static clearStorage(key) {
    try {
      localStorage.removeItem(key);
    } catch (error) {}
  }
}
Vue.prototype.$storage = Storage;

其他配置:

  • Events:对全局事件做一个封装,这里针对每一个组件和每一个自定义事件用了一个简单的工厂模式, 降低代码的耦合性,解决事件封闭,但是缺点是在每一个组件销毁时需要作事件取消监听(销毁),否则会导致之前的监听事件执行两次,虽然每个子工厂生产出来的都是独特的产品,但是会导致性能降低,所以要做事件销毁处理

    import Vue from "vue";
    class Events extends Vue {//继承Vue的自定义事件,使其直接调用
      constructor() {
        super();
      }
      static getInstance() {//返回当前实例的单例
        if (!Events._instance) {
          Object.defineProperty(Events, "_instance", {
            value: new Events()
          });
        }
        return Events._instance;
      }
      onEvent(_event, _fn) {
        this.$on(_event, _fn);
      }
      onceEvent(_event, _fn) {
        this.$once(_event, _fn);
      }
      emitEvent(_event, _data) {
        this.$emit(_event, _data);
      }
      offEvent(_event, _fn) {
        this.$off(_event, _fn)
      }
    }
    Vue.prototype.$events = Events.getInstance()
  • 全国省市县的JSON文件
    https://gitee.com/DieHunter/myCode/blob/master/shopping/client/shopclient/src/config/city.js

  • 静态Config文件

export default class Config {
  static Agreement = "http://"; //协议
  static BaseUrl = "127.0.0.1"; //请求ip或域名
  static ServerUrl = ""; //多级路径名
  static ServerPort = ":1024"; //端口
  static Path = "/"; //静态文件目录
  static CryptoKey = "tokenkey"; //加密信息关键字
  static RequestPath =
    Config.Agreement + Config.BaseUrl + Config.ServerPort + Config.Path; //服务端静态目录
  static RequestTimeOut = 10 * 1000; //请求超时时间
  static GetCodeTime = 60 * 1000; //邮箱验证码重发时间
  static ShopMaxCount = [1, 2, 3, 4, 5, 6, 7, 8, 9]; //每件商品可购买数量(选择器配置)
  static ServerApi = {
    //接口名
    token: "user/checkToken", //验证token
    user: {
      userLogin: "user/userLogin", //用户登录
      getMailCode: "user/getMailCode", //获取验证码
      updateUser: "user/updateUser", //更新用户
      userReg: "user/userReg" //注册(移动端)
    },
    shop: {
      shopList: "shop/shopList" //获取商品列表
    },
    order: {
      orderList: "order/orderList", //获取订单列表
      addOrder: "order/addOrder", //新增订单
      delOrder: "order/delOrder", //删除订单
      updateOrder: "order/updateOrder" //更新订单状态
    }
  };
  static UploadName = {
    headPic: "upload/headPic" //图片路径
  };
  static UploadKey = {
    headKey: "headPic" //头像上传关键字
  };
  static StorageName = {
    //本地缓存
    Token: "token",
    ShopCar: "shopCar", //购物车列表
    UserInfo: "userInfo" //用户信息
  };
  static EventName = {
    //自定义事件
    SelectKind: "selectKind", //分类选择
    ChangeCount: "changeCount", //修改商品数量
    ShowPicker: "showPicker", //显示,隐藏Picker
    CountShop: "countShop", //购物车商品总价
    SelectAllChild: "selectAllChild", //全选子选项
    SelectParent: "selectParent", //全选父选项
    IsLogin: "isLogin", //登录成功
    UploadPic: "uploadPic" //上传图片
  };
  static DefaultPageConfig = {
    //默认分页配置
    shopType: "",
    picType: "",
    keyWord: "",
    page: 1,
    isactive: true,
    pageSize: "",
    totalPage: 1,
    orderId: "",
    sort: "1",
    orderState: ""
  };
}
  • 邮箱类型选择配置
export default class Mail {
  static address = [
    "@qq.com",
    "@gmail.com",
    "@yahoo.com",
    "@msn.com",
    "@hotmail.com",
    "@aol.com",
    "@ask.com",
    "@live.com",
    "@0355.net",
    "@163.com",
    "@163.net",
    "@263.net",
    "@3721.net",
    "@yeah.net",
    "@googlemail.com",
    "@mail.com"
  ];
}
  • 商品类型
export default class ShopType {
  //商品类型,图片类型,订单状态
  static shopType = [
    { name: "炒货", val: "0" },
    { name: "果味", val: "1" },
    { name: "蔬菜", val: "2" },
    { name: "点心", val: "3" },
    { name: "粗茶", val: "4" },
    { name: "淡饭", val: "5" }
    // { name: "其他", val: "6" },
  ];
  static picType = [
    { name: "单个商品", val: "0" },
    { name: "轮播图", val: "1" },
    { name: "分类", val: "2" },
    { name: "主题", val: "3" },
    { name: "其他", val: "4" }
  ];
  static orderState = [
    { name: "未付款", val: "0" },
    { name: "已付款", val: "1" },
    { name: "未发货", val: "2" },
    { name: "已发货", val: "3" },
    { name: "已完成", val: "4" },
    { name: "已退款", val: "5" }
  ];
}

全局Store

  • 全局store没有用Vuex,而是用本地缓存做了一个数据存储,在src下新建store文件夹,并新建store.js文件将所有的状态值汇总并暴露,这里我们简单搭建一下购物车,在shopCar中新建数据model层state和命令控制controller层action

  • store.js

    import Vue from 'vue'
    import ShopCar from "./shopCar/action"
    Vue.prototype.$store = {
      ShopCar
    }
  • state.js

    import Vue from "vue"
    import Config from "../../config/config"
    export default class State extends Vue {
      constructor() {
        super()
      }
      set shopCar(val) {//写数据
        this.$storage.saveStorage(Config.StorageName.ShopCar, val)
      }
      get shopCar() {//读数据
        return this.$storage.getStorage(Config.StorageName.ShopCar) || []
      }
    }
  • action.js

import State from "./state"
import Vue from "vue"
import Config from "../../config/config"
const {
  EventName
} = Config;
export default class Action extends Vue {
  constructor() {
    super()
    this._state = new State()
  }
  set state(val) {
    this._state.shopCar = val
  }
  get state() {
    return this._state.shopCar
  }
  countShopItem() {//修改商品数量
    
  }
  delShopItem() {//删除商品
    
  }
  selAllChild() {//全选
    
  }
  filterSelect() {//刷新商品列表
    
  }
  delSelShop() {//删除选择商品
    
  }
}

引入所有包

import Vue from 'vue'
import App from './App'
import router from './router'
import "./style/main.less"
import 'mint-ui/lib/style.css'
import MintUI from 'mint-ui'
import './utils/axios'
import './utils/cryptoTool'
import './utils/storage'
import "./event/event"
import "./store/store"
Vue.use(MintUI);
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: {
    App
  },
  template: '<App/>'
})

到此为止,前端商城准备工作全部完成,下一篇文章正式开始进入开发