从零开始,搭建一个简单的购物平台(十三)前端商城部分
从零开始,搭建一个简单的购物平台(十二)前端商城部分:
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/>'
})
到此为止,前端商城准备工作全部完成,下一篇文章正式开始进入开发
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY