# vue-shop **Repository Path**: big-frontend/vue-shop ## Basic Information - **Project Name**: vue-shop - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-12-02 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vue-shop ## 一、加载首页数据 ``` /goods/list { start:0, limit:8 } ``` ```js //1.前端代码实现 //只取八条数据,从第一开始获取 export default { data() { return { limit: 8, start: 0, goodsList: [] }; } mounted() { this.initData(); }, methods: { initData() { this.$http .get("/goods/list", { //通过params属性传递参数给后端 params: { start: this.start, limit: this.limit } }) .then(res => { if (res.data.code == 200) { this.goodsList = res.data.result; this.total = Math.ceil(res.data.total / this.limit) * 10; } }); } } }; ``` ```js //后端业务 router.get('/goods/list', async (ctx) => { var {start,limit} = ctx.query; var total = await GoodsModel.find({}).count(); var data = await GoodsModel.find({}).skip(Number(start)) .limit(Number(limit)); ctx.body = { code: 200, msg: "首页数据请求成功", result: data, //给前端设置分页 total:total } }) ``` ## 二、分页 ```js //前端代码 //total 10为只有1页 为30就有3页 ``` ```js methods:{ getPage(page) { //改变从哪一个位置开始查询 this.start = (page - 1) * this.limit; this.initData(); } } ``` ## 三、价格的升序和降序 ``` //对goodsList进行升序和降序 ``` ``` //前端代码 价格 {{(sortFlag==1)?'':''}} ``` ```js methods:{ compareUp(value) { return (a, b) => { return a[value] - b[value]; }; }, compareDown(value) { return (a, b) => { return b[value] - a[value]; }; }, handleSort() { this.sortFlag = this.sortFlag == 1 ? -1 : 1; if (this.sortFlag == 1) { this.goodsList.sort(this.compareUp("salePrice")); } else { this.goodsList.sort(this.compareDown("salePrice")); } } } ``` ## 四、根据价格区间进行排序 ```js methods:{ handlePrice(gt,lt){ this.$http({ url:'/goods/price', method:"get", //传递gt,和lt给后台 params:{ gt, lt } }).then(res=>{ if(res.data.code==200){ this.goodsList = res.data.result; this.total = 10; } }) }, } ``` ```js /* 根据价格区间查询 */ router.get("/goods/price", async ctx => { var { gt, lt } = ctx.query; var data = await GoodsModel.find({ salePrice: { $gt: gt, $lt: lt } }) if (data.length) { ctx.body = { code: 200, msg: "数据请求成功", result: data, total: data.length } }else{ ctx.body = { code:1001, msg:"没有数据" } } }) ``` ## 五、默认 ```js 默认 ``` ```js methods:{ handleDefault(){ this.initData() } } ``` ## 六、添加到购物车 ```js methods:{ addCart(productId){ this.$http({ method:"post", url:'/users/addCart', data:{ productId } }).then(res=>{ this.$message({ message:res.data.msg, duration:1000, type:"success" }) }) } } ``` ```js //后端代码 //添加到购物车 router.post('/addCart', async ctx => { var userId = "100000077"; var { productId } = ctx.request.body; var goodsData = await GoodsModel.findOne({ productId: productId }); // productNum,checked var obj = JSON.parse(JSON.stringify(goodsData)); obj.productNum = 1; obj.checked = true; var userData = await UsersModel.findOne({}); //看cartList是否有我们要添加的数据 if (userData.cartList.every(item => item.productId != productId)) { await UsersModel.update({ userId: userId }, { $push: { "cartList": obj } }) ctx.body = { msg:"添加成功", code:200 } }else{ ctx.body = { msg:"已经添加到购物车", code:200 } } }) ``` ## 七、登陆模块 #### 7-1 跨域访问服务器上的cookie ```js //1.前端代码的配置 main.js axios.defaults.withCredentials = true axios.defaults.crossDomain = true; //允许跨域访问cookie ``` ```js //2.配置服务器 app.js app.use(cors({ origin:"http://192.168.14.57:8080", //配置允许跨域的域名 credentials:true })) ``` #### 7-2 实现登陆功能 ``` 1.前端获取用户和密码 2.携带用户和密码向后台发送http请求 3.后端接收用户和密码 4.向数据库查询 5.将结果返回给前端 ``` ```js //1.前端获取用户和密码 //2.携带用户和密码向后台发送http请求 确 定 methods:{ handleLogin(){ if(this.form.username && this.form.pass){ this.$http({ url:"/users/login", method:"post", data:{ userName:this.form.username, userPwd:this.form.pass } }).then(res=>{ console.log(res) }) } } } ``` ```js //3.后端接收用户和密码 ctx.request.body // 登陆模块 router.post('/login',async ctx=>{ var data = ctx.request.body; }) ``` ```js //4.向数据库查询 router.post('/login',async ctx=>{ var data = ctx.request.body; var res = await UsersModel.findOne(data); //没有的时候null 有的会返回数据 console.log(res) }) ``` ```js //5.将结果返回给前端 // 登陆模块 router.post('/login',async ctx=>{ var data = ctx.request.body; var res = await UsersModel.findOne(data); if(res){ ctx.body = { code:"200", msg:"登陆成功", successName:res.userName } }else{ ctx.body = { code:"400", msg:"用户名和密码错误" } } }) ``` ```js //前端处理代码 methods:{ handleLogin(){ if(this.form.username && this.form.pass){ this.$http({ url:"/users/login", method:"post", data:{ userName:this.form.username, userPwd:this.form.pass } }).then(res=>{ //登陆成功 if(res.data.code==200){ this.$message({ message:res.data.msg, duration:1000, type:"success" }) this.successName = res.data.result this.dialogFormVisible = false; }else{ //用户名和密码错误 this.$message({ duration:1000, message:res.data.msg, type:"error" }) } }) }else{ this.$message({ message:"用户名和密码不能为空", duration:1000, type:"error" }) } } } ``` #### 7-3 使用cookie记录登陆的状态 ```js //1.登陆成功设置cookies router.post('/login',async ctx=>{ var data = ctx.request.body; var res = await UsersModel.findOne(data); if(res){ ctx.cookies.set("userId",res.userId,{ maxAge:1000*60*60 }) ctx.cookies.set("userName",res.userName,{ maxAge:1000*60*60 }) ... }) ``` ```js //2.配置路由检查一下登陆的状态 //检查一下登陆的状态 router.get('/checkLogin',async ctx=>{ var userId = ctx.cookies.get("userId"); if(userId){ ctx.body = { code:200, msg:"登陆成功", result:ctx.cookies.get("userName") } }else{ ctx.body = { code:1001, msg:"未登录" } } }) ``` ```js //3.页面初始加载时,调用/user/checkLogin检查用户是否登陆 mounted(){ this.$http('/users/checkLogin').then(res=>{ if(res.data.code==200){ this.successName = res.data.result }else{ this.$message({ message:"未登陆", duration:1000, type:"warning" }) } }) } ``` #### 7-4 退出登陆 ```js //1.配置路由 清除cookies router.post('/logout',async ctx=>{ ctx.cookies.set("userId","",{ maxAge:-1 }) ctx.cookies.set("userName","",{ maxAge:-1 }) ctx.body ={ code:200, msg:"退出登陆" } }) ``` ```js //2.前端代码 methods:{ handleLogout(){ this.$http.post('/users/logout').then(res=>{ this.$message({ message:res.data.msg, duration:1000 }) this.successName = "" }) } } ``` #### 7-5 登陆拦截 ```js //使用中间件 //ctx.path 获取前端向后台访问的接口 app.use( async (ctx,next)=>{ console.log(ctx.path) // 登陆才可以访问后端其他的接口 if(ctx.cookies.get("userId")){ await next() }else{ //没有登陆的情况后端有些接口时可以访问 if(ctx.path =="/users/login" || ctx.path =="/goods/list" || ctx.path == "/users/Logout"){ await next() }else{ ctx.body = { code:1001, msg:"未登陆" } } } }) ``` ## 八、购物车模块 #### 8-1 购物车查询 ```js router.get('/cartList',async ctx=>{ var data = await UsersModel.findOne({}); var res = data.cartList; ctx.body ={ code:200, result:res } }) ``` #### 8-2 购物车的删除 ```js //后代代码 router.post('/cartList/del',async ctx=>{ var {productId} = ctx.request.body; var userId = ctx.cookies.get("userId"); var data = await UsersModel.update({userId:userId},{$pull:{cartList:{productId:productId}}}); if(data.ok==1){ ctx.body = { code:200, msg:"删除成功" } }else{ ctx.body = { code:1001, msg:"删除失败" } } }) ``` ```js //前端代码 methods:{ handleDelete(productId) { console.log(productId); this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }) .then(() => { this.$http .post("/users/cartList/del", { productId }) .then(res => { console.log(res); this.initData(); }); }) .catch(() => {}); } } ``` #### 8-3 购物车的修改 ```js //$set //前台的代码 tips 传递item ``` ```js methods:{ async onChange(item){ var {productNum,productId,checked} = item; await this.$http.post('/users/cartList/edit',{ productNum, productId, checked }) } } ``` ```js //后台代码 router.post('/cartList/edit',async ctx=>{ var {productNum,productId,checked} = ctx.request.body; var userId = ctx.cookies.get("userId"); var data = await UsersModel.update( {userId:userId,"cartList.productId": productId},{$set:{ "cartList.$.productNum":productNum, "cartList.$.checked":checked }}); if(data.ok==1){ ctx.body ={ msg:"修改成功", code:200 } } }) ``` ## 九、路由守卫 ```js Tips:一定要配置再路由地址所对应的主组件 // 路由守卫 beforeRouteLeave (to,from,next) { this.$http('/users/checkLogin').then(res=>{ if(res.data.code == 200){ next() }else{ this.$message({ message:res.data.msg, duration:1000 }) } }) } }; ```