Vue项目 | 您所在的位置:网站首页 › 关于咖啡的app › Vue项目 |
SPA项目-瑞幸咖啡
一、项目介绍1.1、基本情况1.2、实现的功能1.2.1、静态页面实现1.2.2、动态效果实现(接口)
1.3、项目使用到的相关技术
二、项目的业务流程(实现)2.1、登录2.1.1、登录的流程
2.2、首页2.2.1、首页轮播图源码2.2.2、点击商品分类获取商品
2.3、详情页(商品详情)2.4、详情页(获取评论)2.5、详情页(加入购物车)2.6、菜单页2.6.1、商品的显示(经典菜单)2.6.2、商品的显示(瑞纳冰季)2.6.3、显示商品详情
2.7、地址页2.7.1、显示地址2.7.2、添加地址
2.8、订单页2.9、添加评论页
说实话,在写这篇博客之前,我想了很久要不要写,写的话无疑是一项工作量巨大的任务,但是扪心自问,这也是一次总结提升的机会,特别对于像我这样新入门的菜,,不新手来说。
好了,不说废话了,以下将开始总结手机应用瑞幸咖啡项目的实现(只实现了部分页面及功能),路过的大佬可以滑走了! 一、项目介绍 1.1、基本情况本次项目使用vue框架实现,采用前后端配合的方式(即前端实现页面及数据渲染),后端提供接口(数据处理)。 瑞幸咖啡APP是一款咖啡类的购物APP,商品以咖啡类为主,业务流程从APP的登录到加入购物车,到支付成功。 由于水平有限,仅实现了部分页面和功能,由于是多人协作,实现的效果各有差异。 1.2、实现的功能 1.2.1、静态页面实现以下是部分静态页面效果 首页 菜单页 商品详情页 我的页面 订单页此外还有购物车页面,地址页面,新增地址页面,个人资料页面,确认订单页面,取消订单页面等等,页面太多,就不一一列举了。 1.2.2、动态效果实现(接口)作为一个完整的项目,必须得有前后端交互功能,如果还有新入坑的不懂前后端交互,我可以简单介绍下。 前端:静态页面,通过接口向后端发出请求,拿到动态数据渲染在页面,一句话总结,前端做的就是用户看得到的部分; 后端:接收前端发来的请求,从数据库中查询数据,并返回给前端,也就是说,后端做的是用户看不到的部分。 在本次项目中,共实现了以下动态效果(我负责的部分) 首页通过商品类型获取对应类型的商品 首页点击图片获取该商品的详细信息 详情页获取该商品的所有评论信息 详情页将该商品加入购物车 购物车页面点击结算创建订单 订单页点击商品添加评论信息 1.3、项目使用到的相关技术首先,通过搭建脚手架创建项目开发环境; 在项目开发中,使用了mock数据,在没有后端接口的情况下模拟实现渲染; 使用了axios向后端发送请求,还是用了拦截器,这是在发送请求时携带token信息的;’ 在进行页面跳转时,由于我们做的是SPA(单页面应用),需要用路由跳转,动态路由传参等‘; 以及路由守卫,以此来判断用户是否登录(能否显示页面),懒加载技术可以提高页面加载性能; 在APP里经常会有一些表单验证或者遮罩层的结构,我们在项目中引入了第三方组件(Vant等); 在进行组件通信时,还用到了vueX来保存全局数据,使用起来非常方便; 在发起请求时,由于前后端分离,势必造成跨域的问题,我们使用反向代理来解决跨域; 到最后,到项目整体的打包。 以上相关技术基本都属于vue系列技术,(可以参考我之前的博客, vue入门系列)我们在项目中或多或少都使用到。 二、项目的业务流程(实现)第一次做vue项目,有很多瑕疵,以后有机会会完善一下,进来的大佬也可以在评论区指导指导,本人绝对虚心受教,刚入坑的小伙伴也可以交流交流! 2.1、登录登录这一部分不是我写的,但是基本实现还是知道的。由于原APP是没有注册页面,(好像大部分APP都是直接登录),所以只实现了登录的功能。 2.1.1、登录的流程 1,用户输入手机号,前端进行手机号格式验证; 2,若格式合法,用户点击获取验证码; 3,前端发请求,后端返回验证码; 4,用户输入验证码,并点击登录; 5,若验证码正确,后端返回登录成功信息,同时返回token信息; 6,前端接收token信息,并保存在本地(我们保存在cookie里) 获取验证码,并验证手机格式 export default { name: "Centent1", data(){ return { tel:'', code:'' } }, methods: { fn() { //获取验证码 axios({ url: "/api/user/sendtel", params: { tel: this.tel, }, // method:'get', 默认是get请求 }) .then((res) => { if(res.data.code=="1"){ // console.log(res.data); console.log('发送成功'); this.$store.state.code = res.data.data }else{ console.log('发送失败'); } }) }, testphone() { var phone = this.tel; this.$store.state.tel = this.tel if (!/^1[3456789]\d{9}$/.test(phone)) { Toast.fail('手机号有误!'); return false; }else{ Toast.success('手机号可用!'); } }, }, };验证手机号格式有误: 登录成功,并保存token信息 export default { name: "Centent2", methods: { fn() { console.log(this.$store.state.tel); axios({ url: "/api/user/login", params: { tel: this.$store.state.tel, code: this.$store.state.code, }, // method:'get', 默认是get请求 }).then((res) => { if(res.data.code=='1'){ // console.log(res.data.data); let date = new Date(); date.setDate(date.getDate()+7) document.cookie = `token=${res.data.data};expires=${date}`; console.log(document.cookie); this.$router.push('/index') }else{ console.log('登录失败'); } }); }, }, };获取到验证码,输入验证码 注意:由于项目中使用了路由守卫,部分页面如商品详情页,订单页在未登录状态时(即本地没有token信息) 无法访问。 未登录时浏览器的cookie 登录成功后浏览器的cookie 2.2、首页首页这部分是我写的,所以我会说的更详细一点。 首先我们要知道,首页是可以直接访问,也就是不受token的影响,并且在首次登录成功后,也会跳转到首页。 首页的静态页面前面已经看过了,动态效果只有一个:点击商品类型获取对应的商品(轮播图就不说了吧,swiper组件实现的,有兴趣可以研究研究,下面我放上源码仅供参考) 2.2.1、首页轮播图源码 import Swiper from "swiper"; import "swiper/css/swiper.css"; export default { name:"banner", mounted(){ new Swiper ('.swiper-container', { speed:800, autoplay:true, // 如果需要分页器 pagination: { el: '.swiper-pagination', }, }) } } .swiper-container{ width: 100%; height: 2.42rem; position: relative; } .swiper-container img{ width: 100%; height: 100%; } .swiper-pagination{ position: absolute; bottom: 0.7rem; } 2.2.2、点击商品分类获取商品我们可以看到,首页总共有4个分类,后端同学帮我们在数据库存好了,从左往右商品类型对应typeId为 4,5,6,7 这一块儿的实现方式有很多,如动态组件,组件通信等等,我推荐使用vueX,真的谁用谁说好! 实现思路: 1,首页默认加载第一种分类,那就在加载页面时发送typeId为4 的请求,获取数据并渲染; 2,点击其他分类时,再发送一次请求,获取对应类型的商品; 3,模板渲染时的值都来自vueX中的state,所以不用担心 默认第一种的数据会和点击其它分类时数据重复。(我 就遇到过这个问题,当时用动态组件做的)。 具体实现步骤(直接上源码) //store/index.js(vueX)中的代码 import vueX from 'vuex' import Vue from 'vue' import axios from '../utils/request.js' Vue.use(vueX) export default new vueX.Store({ state: { shopinfo: [], tel: '', code: '', isshow: false, orderInfo: ["全部", "立等可取", "预约订单"], outerInfo: ["门店自提", "送货上门", "瑞即购"], isLoading: false, }, mutations: { //state:store中的state change(state, payload) { state.shopinfo = payload.data // console.log(state.shopinfo); }, changeload(state, payload) { // console.log(payload); state.isshow = payload }, changeIsLoading(state, payload) { state.isLoading = payload.isLoading; } }, actions: { //context:store对象 change1(context) { axios({ url: "/api/goods/findGoodsByType", params: { typeId: 4, } }) .then(res => { console.log(res.data.data); context.commit('change', { //将请求结果传给mutations data: res.data.data }) }) }, change2(context, payload) { // console.log(payload); axios({ url: "/api/goods/findGoodsByType", params: { typeId: payload, } }) .then(res => { context.commit('change', { //将请求结果传给mutations data: res.data.data }) }) }, } }) //导航组件中的代码 export default { data(){ return { shoplist:this.$store.state.shopinfo, } }, //发送请求,获取数据 created(){ //组件里派发action this.$store.dispatch('change1') console.log(this.shoplist); }, methods:{ tiao(id){ this.$router.push('/info/'+id) }, toshopcart(){ this.$router.push('/Shop') } } }点击效果图(不会做gif图…)… (vueX的安装及使用可以参考我的博客) 2.3、详情页(商品详情)这个也是我写的,哈哈! 前面我们说了,点击首页中的商品获取商品的详细信息,通过动态路由传参,将商品的id(不是类型id)传到详情页,再发送请求。 实现思路: 1,首页点击商品,将商品id通过路由传参传递到详情页; 2,详情页接收id值,发起请求,获取数据,渲染。 //点击商品,获取商品详情 import axios from '../utils/request.js' export default { data(){ return { shopinfo:[] } }, created(){ axios({ url:'/api/goods/findGoodsByGid', params:{ id:this.$route.params.id } }) .then(res=>{ if(res.data.code=='1'){ // console.log('查询成功'); this.shopinfo = res.data.data // console.log(this.shopinfo); }else{ console.log('查询失败'); } }) } }获取id为15的商品信息 2.4、详情页(获取评论)获取评论也是在详情页,所以共用一个商品id,获取评论也需要传商品id。(这个应该都能理解吧!) 实现思路: 1,接收传来的商品id值; 2,发请求,获取评论信息。 获取商品的评论信息 import axios from 'axios'; export default { data(){ return { comminfo:[] } }, created(){ axios({ url:"/api/comment/findCommentsByGid", params:{ gid:this.$route.params.id } }) .then(res=>{ // console.log(res.data); this.comminfo = res.data.data }) } }获取到的部分评论信息: 是不好奇评论信息哪来的,往下看就知道了! 2.5、详情页(加入购物车)同样是在详情页,这里我用了一个vant组件,结合自己手敲的代码。 先看效果图:(点击页面原有的加入购物车,弹出遮罩层) 遮罩层里的信息和获取商品详情的代码类似,我就不贴出源码了。 加入购物车实现思路: 1,拿到传来的id值; 2,用户修改商品数量,获取相关参数,发请求。加入购物车源码: jia() { axios({ url:'/api/cart/addCart', method:'post', data:{ "gid": 12, "number": 3, "price": 2, "total": 45, "uid": 4 } }) .then(res=>{ if(res.data.code=='1'){ console.log(res.data); Toast.success("加入成功!"); }else{ Toast.fail("加入失败!"); } })如图为加入购物车成功效果图: 此时,数据库中购物车对应的表就有相关数据了。 2.6、菜单页菜单页相关功能不是我负责的,所以我会说的没有那么详细,不过还是会附上源码的。 菜单页,也就是各种咖啡或者奶茶下单,查看详情等一系列操作。 2.6.1、商品的显示(经典菜单)菜单页的商品是在页面加载时渲染的,默认是第一种,点击其他类型时显示对应商品,实现思路和首页的一致。 created() { Axios({ url: "/api/goods/findGoodsByHot", }).then((res) => { this.goods = res.data.data; }); Axios({ url: "/api/goods/findGoodsByType", params: { typeId: 2, }, }).then((res) => { this.goods1 = res.data.data; }); Axios({ url: "/api/goods/findGoodsByType", params: { typeId: 3, }, }).then((res) => { this.goods2 = res.data.data; }); }, methods: { ding(index) { this.$router.push("/Detail/" + index); }, },点击其他分类时效果图: 2.6.2、商品的显示(瑞纳冰季)这一部分是一个瀑布流结构,实现思路比较简单,获取商品数据,按瀑布流的结构渲染。 import Axios from "../untils/request"; export default { name:"Pu", data(){ return { goods:[],typeId:0, } },created(){ Axios({ url: "/api/goods/findGoodsByType", params:{ typeId:8 } }).then((res) => { this.goods=res.data.data; }); } }效果图:(以下图片的排列方式就是瀑布流,交叉的感觉) 2.6.3、显示商品详情和主页点击图片跳转到详情页一样,思路我就不写了,都是把商品id传过去,然后发请求,获取数据再渲染。 附上源代码: export default { name:"Dinfo", data() { return { shopinfo: [], }; }, created() { Axios({ url: "/api/goods/findGoodsByGid", params: { id: this.$route.params.id, }, }).then((res) => { this.shopinfo = res.data.data; }); }, };不同的是,两个详情页结构有点差别。 2.7、地址页地址页是从菜单页跳转过去的,菜单页有个配送方式(自提/外送)细心的同学可能看到了。点击外送时,会跳到地址页,可以进行新增地址等操作。 2.7.1、显示地址实现思路: 1,拿到用户对应的id值; 2,发请求,获取地址信息; 3,渲染到页面。 created() { Axios({ url: "/api/addr/selectAddrByUserId/1", }).then((res) => { res.data.data.forEach((item) => { this.list.push({ id: item.id, name: item.userName, tel: item.tel, address: item.detailAddr + item.houseNumber, isDefault: item.defaultAddr == 1 ? (this.isDefault = true) : (this.isDefault = false), }); }); }); },获取地址信息效果图: 2.7.2、添加地址既然可以查,当然也可以加,不得不说参与到项目的每位同学都很给力啊。点个赞。 实现思路: 1,添加地址为post请求,参数较多; 2,发请求。 methods: { onSave(con) { Toast.success("保存成功"); this.$router.push("./Outering"); Axios({ url: "/api/addr/addAddr", method: "POST", data: { defaultAddr:1, detailAddr: con.province+con.city+con.county, houseNumber: con.addressDetail, id:con.id, label: "家", sex: 1, tel: con.tel, userId: 1, userName: con.name, }, }).then((res) => { console.log("res.data",res.data); });添加地址: 2.8、订单页订单页就是在订单创建出来后,查询出来的结果。订单的创建是在购物车点击结算创建的(前面提到过)。 实现思路: 1,拿到用户id; 2,根据用户id查询所有订单信息,再渲染。 查询订单 created(){ Axios({ url:"/api/order/selectOrdersByUid/4" }).then(res=>{ this.order=res.data.data; this.desc=res.data.data[0].orderDetailResps; }) },注意:订单只有创建成功后才能够查询。 2.9、添加评论页添加评论是在商品完成支付后才能够评论,相信大家都不陌生,没有哪款电商APP会让你购买商品之前评论吧。 由于原页面没有添加评论页面(或者说我们没找到),所以我自己简简单单加了个页面(简陋版) 写的不好看(作为前端开发人员…),主要实用就行。 添加评论实现思路: 1,从订单页传来商品id以及用户id,再获取文本框里输入的内容; 2,采用post请求,添加评论。(现在知道为什么会有那么多评论信息了吧!) methods:{ back(){ this.$router.back(); }, addcomm(){ // console.log(this.txt); axios({ url:'/api/comment/addComment', method:'post', data:{ gid:this.$route.params.id, uid:9, comment:this.txt } }) .then(res=>{ if(res.data.code=='1'){ Toast.success('发布成功!'); //清空文本框 console.log(this.txt); this.txt = '' }else{ Toast.fail('发布失败!'); } }) } }添加成功的评论就会在详情页显示啦! ============================================ 今天的内容就先到这儿吧,写了快一天了,后面的内容我会补上的!点个关注,期待下后面的精彩内容吧! 后续篇戳我阅读! |
CopyRight 2018-2019 实验室设备网 版权所有 |