【Vue】仿小米商城系统(一)
文章目录
前言
本项目是基于Vue全家桶的仿小米商城系统,系列笔记(已完结)如下👇🏻
【Vue】仿小米商城系统(一)
🐶项目地址:
源码点击这里👉vue仿小米商城源码
这里是小飞侠Pan🥳,立志成为一名优秀的前端程序媛!!!
本篇博客收录于我的github前端笔记仓库中,持续更新中,欢迎star~
👉https://github.com/mengqiuleo/myNote
一、项目概述
项目介绍
本项目是基于Vue全家桶的仿小米商城系统,商城的流程如下:
- 登录 -> 产品首页 -> 产品站 -> 产品详情
- 购物车 -> 订单确认 -> 订单支付 -> 订单列表
该项目是对小米商城系统的模仿,实现了从浏览商品到结算商品的整个过程。使用Scss、mixin来对公共样式抽离;对不同页面进行组件复用;商品展示图片使用vue-lazyload实现懒加载;通过vuex实现商品的状态管理,最终实现了登录、浏览商品并加入购物车、结算等功能。
项目源码: vue仿小米商城源码
商城页面与组件
技术栈
商城各页面展示
商品首页
首页各个组件的静态代码实现,并实现了图片懒加载,实现了swiper轮播图。
产品站
产品站页面吸顶组件、参数组件实现。
商品详情
商品详情交互接口实现。
登录页面:账号 admin 密码 admin
登录页面交互和接口完整代码实现。
订单确认
订单确认页面中部分静态模块实现以及接口功能实现。
购物车页面
购物车头部组件以及购物车所有功能的动态交互实现。
订单支付页面
订单结算交互实现,同时包含微信支付和支付宝支付同后台对接。
支付宝支付
微信支付
订单列表
项目源码:
点击这里👉 : vue仿小米商城源码
二、项目开发前准备
跨域解决
jsonp
项目里面使用jsonp,先安装
cnpm i jsonp --save-dev
jsonp不是一个请求,而是一个js脚本。利用了js脚本加载没有限制来进行访问.
在浏览器控制台的XHR中没有,而是在JS中出现(是一个JS脚本)。
在项目中导入,import jsonp from 'jsonp'
然后在mounted中设置,
mounted(){
let url = "https://www.baidu.com";
jsonp(url,() => {
})
}
nginx
接口代理 - 通过修改Nginx服务器配置来实现
前端修改,后台不动
在根目录创建配置文件:vue.config.js
,在里面配置以下内容:
nodejs服务器遵循的是commonjs规范
设置代理后,
module.exports = {
devServer:{
host:'localhost',
port:8080,
proxy:{
'/api':{
target:'http://mall-pre.xxx.cn',
changeOrigin:true,
pathRewrite:{
'/api':''
}
}
}
}
}
// 注意:在target里面需要写上接口代理的目标地址
比如有很多接口:
- http://mall-pre.xxx/server/a.cn
- http://mall-pre.xxx/server/b.cn
- http://mall-pre.xxx/server/c.cn
原理: 因为我们需要使用的接口地址可能很多,不可能挨个去进行拦截。所以,这里可以设置一个虚拟的地址/api,实际上,是没有这个地址的。当拦截到/api时,就将主机的点设置为原点(changeOrigin:true),然后添加路径的转发规则,将/api 置为空,转发时就没有/api了
项目目录结构
- api: 对api的一些处理
- util:对公共的方法的定义、封装
- store:使用Vuex的目录
- pages:项目页面文件
- storage:数据储存相关
- assets:小图片、样式文件等
- components:组件
- router.js:路由
需要注意的是:axios是一个库,并不是vue中的第三方插件,所以使用时需要在每个页面进行导入操作,这样就很麻烦。我们可以使vue-axios将axios的作用域对象挂载到vue实例中,这样就可以在需要使用的时候用this来调用。
Vue.use(VueAxios, axios)
Storage封装
- storage本身虽然有API,但是只是简单的key/value形式,
- storage只能存储字符串,需要手工转化为json对象,
- 并且storage只能一次性的清空,不能进行单个的清空,
- 我们要向storage中存储一些更复杂的数据形式,所有我们需要对storage进行封装。
这里封装的是sessionStorage,实际上就是可以在sessionStorage存储JSON对象,并且可以对这些对象进行一些操作:
setItem();
getItem();
getStorage();//获取所有数据
clear();
/**
* Storage封装
*/
const STORAGE_KEY = 'mall';
export default{
//存储值
setItem(key,value,module_name){
if(module_name){
let val = this.getItem(module_name);
val[key] = value;
this.setItem(module_name);
}else{
let val = this.getStorage();
val[key] = value;
window.sessionStorage.setItem(STORAGE_KEY,JSON.stringify(val));
}
},
//获取某一个模块下面的属性 :user下面的username
getItem(key,module_name){
if(module_name){
let val = this.getItem(module_name);
if(val) return val[key];
}
return this.getStorage()[key];
},
getStorage(){
return JSON.parse(window.sessionStorage.getItem(STORAGE_KEY) || '{}');
},
clear(key,module_name){
let val = this.getStorage();
if(module_name){
if(!val[module_name]) return;
delete val[module_name][key];
}else{
delete val[key];
}
window.sessionStorage.setItem(STORAGE_KEY,JSON.stringify(val));
}
}
接口错误拦截
- 统一报错
- 未登录统一拦截
- 请求值,返回值统一处理
使用axios的拦截器进行处理
//# 根据前端的跨域方式做调整
axios.defaults.baseURL = '/api';
axios.defaults.timeout = 8000;//超时时间为8秒
// # 响应拦截器:接口错误拦截
axios.interceptors.response.use(function(response){
let res = response.data;//拿到真正的数据
let path = location.hash;
if(res.status == 0) {
return res.data;
}else if(res.data == 10){
if(path!='#/index'){
window.location.href = '/#/login';
}
return Promise.reject(res);
}else{
Message.error(res.msg);
return Promise.reject(res);
}
},(error)=>{
let res = error.response;
Message.error(res.data.message);
return Promise.reject(res);
})
Mock设置
在开发阶段,我们可能还不能拿到API文档,所以可以使用Mock模拟数据来进行数据的交互操作。Mock有以下特点:
-
开发阶段,为了提高效率,需要提前Mock
-
减少代码冗余,灵活插拔
-
较少沟通,减少接口联调时间
使用mock的方法有很多:
- 本地创建json:在本地创建json文件,然后进行调用
- easy-mock平台:将baseURL设置为easy-mock的接口地址,调用时和正常调用一样
- 集成Mock API(本地集成Mock.js)
不管哪一种方法,都是要自己写mock数据。
其实Mock.js 很像 json-server。只不过是一个用在单页面,一个用在vue项目中。
在这个项目里并没有进行Mock.js设置,因为这里的后台完全都有接口数据。
集成Mock API(本地集成Mock.js)
cnpm i mockjs --save-dev
在src中建Mock的API:src/mock/api.js
import Mock from 'mockjs'
Mock.mock('/api/user/login', {
"status": 0,
"data": {
"id": 12,
"username": "admin",
"email": "admin@51purse.com",
"phone": null,
"role": 0,
"createTime": 1479048325000,
"updateTime": 1479048325000
}
})
之后在main.js设置一个mock的开关:
const mock = true
if(mock){
require('./mock/api')
}
import是预编译加载,刚打开就会被加载。而require是执行到那一行才会被加载,在这里如果设置mock=false
,用require的话那么就永远不会被加载。
但是如果设置import
,即使是false,也会被加载。
Mock.js比较好的一点就是,它可以设置返回的数据是随机的。
"status": 0,
"data": {
"id" | 10001-11000: 12, //这里设置每次返回的数据是在10001~11000之间,每次不一样
"username": "@cname", //每次生成随机的名字
"email": "admin@51purse.com",
"phone": null,
"role": 0,
"createTime": 1479048325000,
"updateTime": 1479048325000
}