vue-day16----拿到登录的token、登录的逻辑、加入购物车、购物车图标上的数量-count、加入购物车的逻辑判断-Dialog对话框(优化)、Cart/index.vue购物车页面数据渲染、Cart/index.vue购物车页面加减法的接口调用、详情页 商品-详情-评价 切换动画、nginx打包
### 拿到登录的token
①api/index.js中添加user接口:
user: { login: "/v3/login" },
②api/request.js中导出 userLoginApi 接口(注意是post方法):
export const userLoginApi=(data)=>{ return http({ method:"post", data:{...data}, url:api.user.login }) }
③store/index.js中引入 userLoginApi 接口,并在actions中设置请求方法(userLogin):
import { cityApi,userLoginApi } from "@api/request.js"; async userLogin({commit,dispatch},info){ let data=await userLoginApi(info); console.log(data) }
④pages下新建Login/index.vue(利用vant的Form表单、通过辅助函数解构vuex的actions中的 userLogin 方法、当点击提交,触发 onSubmit() 方法的时候执行 this.userLogin(values); 将username和password带过去,即可拿到data数据):
<template> <div> <Header></Header> <van-form @submit="onSubmit"> <van-field v-model="username" name="username" label="用户名" placeholder="用户名" :rules="[{ required: true, message: '请填写用户名' }]" /> <van-field v-model="password" type="password" name="password" label="密码" placeholder="密码" :rules="[{ required: true, message: '请填写密码' }]" /> <div style="margin: 16px;"> <van-button round block type="info" native-type="submit">提交</van-button> </div> </van-form> </div> </template> <script> import Header from "@/components/Home/Header/index.vue"; // 使用vant import Vue from "vue"; import { Form,Field, Button } from "vant"; Vue.use(Form); Vue.use(Field); Vue.use(Button); // 辅助函数 import {mapActions} from "vuex"; export default { components: { Header }, data() { return { username: "", password: "" }; }, methods: { ...mapActions({ userLogin:"userLogin" }), onSubmit(values) { console.log("submit", values); this.userLogin(values); } }, mounted() { console.log(this.$route) }, }; </script> <style scoped> header{ position:static !important; } </style>
⑤router中配置login路由,router中新建login/index.js:
export default{ name:"login", path:"/login", component:()=>import("@pages/Login"), meta:{ title:"登录页面", } }
⑥router/index.js中设置全局路由守卫,在cart和mine的路由下设置meta信息required为true,这样当进入cart页面和mine页面时会先经过路由守卫,没有token值就会进入到login页面:
import login from "./login"; import store from "@store/index.js"; // 全局前置路由守卫 router.beforeEach((to, from, next) => { document.title = to.meta.title; /* cart和mine页面设置了meta信息----required:true,当进入其他页面的时候直接过去,当进入这两个页面的时候先进入路由守卫 */ if (to.meta.required) { // 进入路由守卫时判断有没有token,如果有直接过,如果没有则进入到login页面 if (store.state.token) { next(); } else { next("/login"); } } else { next(); } });
注意:
1、请求方法userLoginApi()的method是post,而不是get
2、vant的Field和Button是自己引入并注册的,vant文档中没有写:Vue.use(Field);Vue.use(Button);
### 登录的逻辑
①router/index.js中全局路由守卫的时候判断如果没有token就跳转到login页面,同时将原本将要跳转的路劲通过params传递给login页面:
router.beforeEach((to, from, next) => { document.title = to.meta.title; /* cart和mine页面设置了meta信息----required:true,当进入其他页面的时候直接过去,当进入这两个页面的时候先进入路由守卫 */ if (to.meta.required) { // 进入路由守卫时判断有没有token,如果有直接过,如果没有则进入到login页面 if (store.state.token) { next(); } else { next({ name: "login", params: { to: to.path } }); } } else { next(); } });
②store/index.js中actions方法(userLogin())中判断如果用户名和密码正确,则触发返回true,否则返回false:
async userLogin({commit,dispatch},info){ let data=await userLoginApi(info); console.log(data) if(data.code==200){ return true; }else{ return false; } }
③Login/index.vue中onSubmit()方法提交时,接收actions中userLogin()的返回值(true或false),如果为true说明store中请求正确,则显示登录成功,并且通过params取值跳转到原本要跳转的页面:
async onSubmit(values) { let result=await this.userLogin(values); if(result){ Toast('登录成功'); this.$router.push(this.$route.params.to); }else{ Toast("用户名或密码错误"); } }
④store/index.js中actions方法(userLogin())中if判断里如果data.code==200,则触发commit():
commit("hanldeLogin",data);
⑥store/index.js的mutations中添加hanldeLogin():(将token存起来,后面操作购物车要用到)
hanldeLogin(state,data){ state.token=data.data.connect_id; localStorage.setItem("token",data.data.connect_id); }
⑦store/index.js的state中添加token:
token:localStorage.getItem("token")||""
注意:
1、vuex中的actions中的方法有返回值,返回值是一个Promise,所以才可以用async搭配await接收userLogin()返回的值。
2、重要逻辑:路由守卫中将原本要跳转的页面路径通过params传递到onSubmit()方法中,当登录成功时再通过params取值跳转到原本要跳转的页面。
3、Toast从vant中引入并注册:Vue.use(Toast); ,它是js组件,可以直接使用:Toast('登录成功');
### 加入购物车
分析:添加到购物车的接口一共需要3个参数:store_id_list、product_id、connect_id。其中connect_id就是前面获取的token,前面两个参数是当前商品中的两个id值,可以通过props传到AddCart组件中。在页面中点击会打印{code: "200", msg: "购物车添加成功", cart:{...}}
①api/index.js中添加购物车接口:
// 购物车接口 cart: { addCart: "/v3/addCart", cartList: "/v3/cartList", increase: "/v3/increase",// 增加 decrease: "/v3/decrease" // 减少 }
②api/request.js中导出 addGoodsCartApi() 方法:
export const addGoodsCartApi=(data)=>{ return http({ method:"get", data, url:api.cart.addCart }) }
③store下新建cart/index.js中定义异步 handleAsyncAddCart() 方法调用 addGoodsCartApi 接口:
import {addGoodsCartApi} from "@/api/request.js"; export default{ state:{ }, actions:{ async handleAsyncAddCart({commit},params){ let data=await addGoodsCartApi(params); console.log(data) } }, mutations:{ }, namespaced:true }
④store/index.js中引入import cart from "./cart";,并注册到modules中modules: {...,cart}
⑤pages/Details/Goods.vue中通过自定义属性将store_id_list和product_id传递给AddCart组件:(注意要用三目做判断)
<AddCart :store_id_list="detailsGoods.productInfo?detailsGoods.productInfo.store_id:''" :product_id="detailsGoods.productInfo?detailsGoods.productInfo.product_id:''"></AddCart>
⑥components/Details/AddCart/index.vue中tap事件触发 handleAsyncAddCart() 方法,将三个参数传递过去(这三个参数传递到request.js中的addGoodsCartApi):
<v-touch tag="div" @tap="addCart()"> <span>明日达</span> <span>加入购物车</span> </v-touch>
import {mapActions} from "vuex"; export default { props:["store_id_list","product_id"], methods: { ...mapActions({ handleAsyncAddCart:"cart/handleAsyncAddCart" }), addCart(){ this.handleAsyncAddCart({ store_id_list:this.store_id_list, product_id:this.product_id, connect_id:this.$store.state.token }); }, }, }
### 购物车图标上的数量-count
①store/cart/index.js中handleAsyncAddCart()方法触发成功后,意味着添加成功,即可以触发commit()方法:
commit("handleAddCart",data.cart); mutations:{ handleAddCart(state,data){ state.count=data.count; state.products=data.products; state.total=data.total; localStorage.setItem("count",data.count); localStorage.setItem("products",JSON.stringify(data.products)); localStorage.setItem("total",JSON.stringify(data.total)); } },
②store/cart/index.js中state设置count、product、total:
state:{ count:localStorage.getItem("count")||"", products:localStorage.getItem("products")?JSON.parse(localStorage.getItem("products")):[], total:localStorage.getItem("total")?JSON.parse(localStorage.getItem("total")):{} },
③components/Details/AddCart.vue中直接拿count值渲染:
<span>{{$store.state.cart.count}}</span>
### 加入购物车的逻辑判断-Dialog对话框(优化)
①components/Details/AddCart/index.vue中全局引入Dialog组件:
import Vue from 'vue'; import { Dialog } from 'vant'; Vue.use(Dialog);
②addCart()方法中添加判断,如果已登录状态则可以添加,如果未登录状态询问是否要跳转到login页面,跳转时将当前路由路劲带过去:
addCart() { this.handleAsyncAddCart({ store_id_list: this.store_id_list, product_id: this.product_id, connect_id: this.$store.state.token }); },
替换为
addCart() { if(this.$store.state.token){ this.handleAsyncAddCart({ store_id_list: this.store_id_list, product_id: this.product_id, connect_id: this.$store.state.token }); }else{ Dialog.confirm({ title:"您还没有登录?", message:"是否需要跳转到登录页面?" }).then(()=>{ this.$router.push({name:"login",params:{to:this.$route.path}}) }).catch(()=>{ Dialog.close(); }) } },
### 购物车的两种状态:一是未登录不可以添加到购物车,二是未登录页可以添加到购物车,但是在付款的时候验证是否登录
### Cart/index.vue购物车页面数据渲染
①api/index.js中添加cartList接口:
// 购物车接口 cart: { addCart: "/v3/addCart", cartList: "/v3/cartList" }
②api/request.js中添加cartListApi接口:
export const cartListApi=()=>{ return http({ method:"get", url:api.cart.cartList }) }
③Cart/index.vue中引入接口:
import {cartListApi} from "@api/request.js";
④Cart/index.vue中定义products、total、count,请求接口数据赋值,进行页面渲染:
data(){ return{ products:[], total:{}, count:"" } }, methods: { async getCartList(){ let data=await cartListApi(); console.log(9999,data) this.getCartInfo(data); }, getCartInfo(data){ this.products=data.cart.products; this.total=data.cart.total; this.count=data.cart.count; } }, created() { this.getCartList(); }
注意:这里用的cartListApi,以及后面用到的increaseApi、decreaseApi,都没有传参数,是因为tiantian-api文件中controller/index.js文件的对应接口都写死了,实际工作中这里是需要传对应的参数的。
### Cart/index.vue购物车页面加减法的接口调用
①api/index.js中添加increase和decrease接口:
cart: { addCart: "/v3/addCart", cartList: "/v3/cartList", increase: "/v3/increase",// 增加 decrease: "/v3/decrease" // 减少 }
②api/request.js中添加increaseApi和decreaseApi接口:
export const increaseApi=()=>{ return http({ method:"get", data:{}, url:api.cart.increase }) } export const decreaseApi=()=>{ return http({ method:"get", data:{}, url:api.cart.decrease }) }
③Cart/index.vue中引入increaseApi和decreaseApi接口:
import {cartListApi,increaseApi,decreaseApi} from "@api/request.js";
④Cart/index.vue中添加increaseHandle()和decreaseHandle():
async increaseHandle(){ let data=await increaseApi(); this.getCartInfo(data); }, async decreaseHandle(){ let data=await decreaseApi(); this.getCartInfo(data); }
⑤Cart/index.vue中为 “-” “+” 号加上tap事件:
<div class="goodsNum"> <v-touch tag="div" @tap="decreaseHandle">-</v-touch> <!-- <input type="text" :value="item.qty" /> --> <p>{{item.qty}}</p> <v-touch tag="div" @tap="increaseHandle">+</v-touch> </div>
注意:购物车页面的数据渲染是通过请求接口而来,将用户信息(token)和一些其他参数传递到后端请求而来。加减法的数据更改是通过接口给后端传递不同的参数来触发请求,后端计算好传递给前端,重新渲染页面。任何的计算都是后端完成,前端通过传不同的参实现逻辑。
### 详情页 商品-详情-评价 切换动画
①pages/Details/index.vue中给router-view加上transition标签,设置name属性:
<transition name="slider-left"> <router-view></router-view> </transition>
②设置样式:
.slider-left-enter{ transform: translateX(100%); } .slider-left-leave-to{ transform: translateX(-100%); } .details_goods{ position: absolute; left:0; top:0; right: 0; bottom: 0; padding-top: .9rem; transition: all .3s; }
③DetailHeader.vue头部在切换的时候会有跳动,它的宽度不能是100%,而要改成375px
注意:可以用vant的切换动画,这是针对DetailHeader的:
<van-tabs v-model="active" animated> <van-tab v-for="index in 4" :title="'选项 ' + index"> 内容 {{ index }} </van-tab> </van-tabs>
### nginx打包
①vue.config.js中module.exports={}中配置publicPath:
module.exports={ publicPath:"./", ... }
②public/index.html中用<%= BASE_URL %>代替 ./:
<link rel="stylesheet" href="<%= BASE_URL %>css/reset.css"> <link rel="stylesheet" href="<%= BASE_URL %>css/font/iconfont.css">
③下载解压nginx包,在conf/nginx.conf文件中添加 /v3 代理:
location /v3 { proxy_pass http://localhost:3000; }
④将dist文件夹复制到nginx/html下,改名为 tiantian
⑤启动nginx:双击nginx.exe文件,此时地址栏输入localhost:80可以进入nginx主页
⑥nginx文件夹cmd打开:nginx -s reload
⑦地址栏访问http://localhost/tiantian即可打开nginx代理下的页面,说明代理成功
注意:
1、<%= BASE_URL %>指的是当前路径,就是vue.config.js中publicPath
2、配置跨域代理(vue.config.js中的跨域地址)的时候如果是ip后面不用加 /,如果是域名后面必须加 /
3、如果是history路由会无效,必须使用hash路由
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结