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路由







猜你喜欢

转载自www.cnblogs.com/wuqilang/p/12521500.html