知识点:

  • IScroll 实现拖动下滑效果
  • lazyload实现懒加载效果
  • Vuex 的使用
  • 加入购物车,购物车的数量加减

商品页面 goods/Index.vue组件

显示所有商品列表,用 IScroll 实现拖动下滑效果, 用 lazyload 实现懒加载效果

<template>
    <div class="box" @touchmove.prevent>
        <ul >
            <li> goods {{type}} </li>
            <li is="Item" v-for="item of arr" :key="item._id" :item="item"></li>
        </ul>
    </div>
</template>

<script>
import Item from "./Item.vue"
import { host } from "../../const"
import IScroll from 'iscroll'
import lazy from '../../directives/lazyload'

export default {
    data(){
        return {
            type : "没有分类",
            arr : []
        }
    },
    components:{
        Item
    },
    mounted(){
        // 通过$emit事件在子组件中自定义事件,通过操作子组件中的事件,向父组件传递参数;
        this.$eventbus.$emit("setTitle", "商品")
    
        this.type = this.$route.params.type;
        
        let url = host+"/goods?_type=_type&_word="+this.type+"&_limit=10&_page=1";
        this.$axios.get(url).then(res=>{
            this.arr = res.data.result;
        })

        var that = this;
        var boxH = document.querySelector(".box").offsetHeight;
        
        var myIScroll;
        setTimeout(function(){
            myIScroll = new IScroll(".box");
            myIScroll.on('scrollEnd', function () {
                if( this.y*-1 == document.querySelector(".box>ul").offsetHeight-document.querySelector(".box").offsetHeight ){
                    //console.log('到底啦')
                }else if( this.y == 0 ){
                    //console.log('到头啦')
                }else{
                    //console.log(this.y)
                }
                lazy.show( boxH, this.y );
            })
            lazy.show( boxH, 0 );
        }, 1000)           
    }
}
</script>

<style lang="scss">
.box{
    overflow: hidden;
}
.box>ul{
    background: #b6e4c5
}
</style>

商品详情页面组件 goods/Detail.vue

<template>
    <div class="detail">
        <h1>{{ title }}</h1>
        <img :src="img">
        <div v-html="content"></div>
    </div>
</template>

<script>
import { host } from "../../const";

export default {
    data(){
        return {
            title: "",
            img: "",
            content: ""
        }
    },
    props:[],
    mounted(){
        let { id } = this.$route.query;

        let url = host+"/goods?_type=_id&_word="+id;
        this.$axios.get(url).then(res=>{
            var obj = res.data.result[0];
            this.title = obj.title;
            this.img = host+"/uploads/"+obj.img;
            this.content = obj.content;
        })
    }
}
</script>

<style lang="scss">
.detail{

}
.detail h1{
    font-size: 14px;
}
.detail img{
    width:200px;
}
</style>

商品列表页 goods/Item组件

实现点击加入购物车功能

<template>
    <li class="item">
        <router-link :to="'/detail?id='+item._id">
            <img :src="initimg" v-lazyload="host+'/uploads/'+item.img"><br>
            {{ item.title }}
            {{ item.price | money("元") }}
            查看详情
        </router-link>
        //在商品列表页添加一个按钮,点击时添加一个事件add();
        <button @click="add(item)"><font class="fa fa-shopping-cart"></font>添加到购物车</button>
    </li>
</template>

<script>
import { host } from "../../const";
import { mapActions } from "vuex";
import timg from "../../assets/images/timg.gif";

var f = {
    filters:{
        money( val, d ){
            return val+d;
        }
    }
}

export default {
    data(){
        return {
            host:host,
            initimg:timg//"/src/assets/images/timg.gif"
        }
    },
    props:["item"],
    mixins:[f],
    mounted(){
        //console.log( host )
    },
    methods:{
        add(item){
            //console.log( 'item:', item )
            // vue希望我们在组件中,调用actions中的方法,actions中再调用mutation中的方法,mutation中改变state数据
            //this.$store.commit("addCart", item);// 用commit调用vuex中mutations中的方法
            //this.$store.dispatch("addCart", item);// 用dispatch调用vuex中actions中的方法
            item.n = 1;
            this.addCart(item); // 先用map把actions中的addCart函数合并到methods中,然后调用它

            this.$toast("商品添加成功")
        },
        ...mapActions(["addCart"])
    }
}
</script>

<style lang="scss">
.item{
    padding-bottom: 20px;
}
.item img{
    width: 2rem;
    height: 2rem;
    border: 1px solid gray;
    border-radius: 5px;
}
</style>

购物车页面 buycar/Index.vue 组件

<template>
    <div class="buycar" @touchmove.prevent>
        <ul>
            <li v-for="(item, ind) of goodslist" :key="ind">
                <img :src="host+'/uploads/'+item.img" />
                {{ item.title }}
                <button @click="update(item, -1)"><font class="fa fa-minus-square-o"></font></button>
                {{ item.num }}
                <button @click="update(item, 1)"><font class="fa fa-plus-square-o"></font></button>
            </li>
        </ul>
    </div>
</template>

<script>
import { host } from '../../const';
import IScroll from 'iscroll'
import { mapActions } from 'vuex';

export default {
    data(){
        return {
            host : ""
        }
    },
    computed:{
        goodslist(){
            // 获取 store 中的 state 中的 goodslist 数据
            return this.$store.state.goodslist;
        }
    },
    methods:{
        update(item, n){
            item.n = n; // 决定是+1还是-1
            this.addCart(item);
        },
        ...mapActions(["addCart"])
    },
    mounted(){
        this.$eventbus.$emit("setTitle", "购物车");
        this.host = host;
        var myIScroll;
        setTimeout(function(){
            myIScroll = new IScroll(".buycar");
        }, 0)

    }
}
</script>

<style lang="scss">
.buycar{
    overflow: hidden;
}
.buycar>ul{
    background: #b6e4c5
}
.buycar img{
    width:3rem;
    height:3rem;
}
</style>

Vuex 仓库 store/index.js

import Vue from 'vue';
import Vuex from 'vuex';    // npm i vuex
Vue.use(Vuex);

// vuex 状态管理
// 创建一个仓库,作用是存储那些被共享出来的数据(数据就是状态)
const store = new Vuex.Store({
    state:{
        goodslist : JSON.parse(localStorage.getItem("goodslist")||"[]")      // 保存那些添加到购物车中的商品
    },
    mutations:{
        // 只是做最后一个state的改变
        addCart(state, payload){
            // state 表示 store 中的 state,可以直接操作
            // payload 表示有效载荷,表示别人使用addCart函数时,传进来的数据
            state.goodslist.push(payload);
            //console.log( '将商品保存到购物车中了 payload:', payload )
        },
        updateNum(state, payload){
            state.goodslist[payload.ind].num += payload.n;  // 不会让视图层自动更新           
            state.goodslist = JSON.parse(JSON.stringify(state.goodslist)); // 让视图自动更新
            //console.log( "updateNum:", state.goodslist[payload.ind] )
        },
        delCart(state, payload){
            state.goodslist.splice(payload, 1);   //根据下标,删除数组中的成员,然后视图自动更新
            //console.log( "delCart:", state.goodslist )    
        }
    },
    actions:{
        // 所有的业务逻辑的代码,及异步的代码,都应该写在actions中
        addCart(context, payload){
            // 判断要添加的这个商品,是否已经保存在goodslist中
            var ind = context.state.goodslist.findIndex(obj=>obj._id===payload._id);            
            if( ind > -1 ){
                // 如果已经存在,则数量进行变更
                if( payload.n == 1 ){
                    // 如果是加法
                    context.commit("updateNum", {ind, n:payload.n})
                }else{ // 减法
                    var i = context.state.goodslist[ind].num-1;
                    if( i == 0 ){
                        // 删除商品
                        context.commit("delCart", ind)
                    }else{
                        // 数量减少
                        context.commit("updateNum", {ind, n:payload.n})
                    }
                }                
            }else{       
                // 如果不存在,则直接追加
                var obj = payload;
                obj.num = 1;
                context.commit("addCart", obj) // 在actions中调用mutations中的方法
            }
        }
    }
})

// 订阅(监听),只要数据发生变化,则回调函数就会被触发
store.subscribe(function(mutations, state){
    localStorage.setItem("goodslist", JSON.stringify(state.goodslist))
})

export default store;

购物车梳理

  1. store/index.js Vuex 管理页面

const store = new Vuex.Store({
state:{
存储数据
goodslist:[] 保存到购物车的商品数据
},
mutations:{
改变数据的方法,在 mutations 不应该写逻辑代码,异步代码,只写逻辑赋值的代码
addCart() 添加
updateNum() 更新商品数量
delCart() 删除商品
},
actions:{
所有的业务逻辑的代码,及异步的代码,都应该写在actions中
},
});
2. 商品列表页…
4. 购物车页 …
Vuex的使用 实现添加购物车,购物车商品数量加减 以及 IScroll 和 lazyload的使用

相关文章: