vue + iview 实现购物车功能

image.png
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name ="viewport" content ="width = device-width,initial-scale = 1.0,user-scalable = no"/>
    <title>shopcart</title>
    <link rel="stylesheet" type="text/css" href="static/css/iview.css">
    <script type="text/javascript" src="static/js/vue.js"></script>
    <script type="text/javascript" src="static/js/iview.min.js"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
            list-style: none;
        }
        header {
            height: 42px;
            width: 100%;
            position: fixed;
            top: 0;
            left: 0;
            background: #fff;
            box-shadow: 0px 0px 20px rgba(0, 0, 0, .1);
            font-size: 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            z-index: 10;
        }
        header span {
            font-size: 14px;
            font-weight: bold;
        }
        footer {
            height: 42px;
            width: 100%;
            position: fixed;
            bottom: 0;
            left: 0;
            background: #fff;
            box-shadow: 0px 0px 20px rgba(0, 0, 0, .1);
        }
        footer ul {
            display: flex;
            flex-direction: row;
            justify-content: space-around;
        }
        footer ul li {
            line-height: 42px;
            text-align: center;
            font-weight: bold;
            font-size: 24px;
            height: 42px;
        }
        footer ul li:nth-child(3) {
            position: relative;
        }
        .num-badge {
            position: absolute;
            top: 0;
            font-weight: normal;
            display: block;
            background: #ed3f14;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            font-size: 9px;
            right: -10px;
            overflow: hidden;
            line-height: 20px;
            text-align: center;
            color: #fff;
        }
        .container {
            margin-top: 42px;
            margin-bottom: 42px;
        }
        .goods-list {
            padding: 8px;
        }
        .goods {
            display: flex;
            padding-top: 10px;
            flex-direction: row;
            justify-content: space-between;
            padding-bottom: 10px;
            position: relative;
        }
        .goods:after {
            content: ' ';
            position: absolute;
            bottom: 0;
            display: block;
            width: 200%;
            left: -50%;
            height: 1px;
            background: #ededed;
            -webkit-transform:scale(0.5);
        }
        .goods img {
            height: 64px;
            width: 64px;
            border-radius: 2px;
        }
        .goods-title {
            font-weight: bolder;
            font-size: 13px;
        }
        .goods-content {
            display: flex;
            flex-direction: column;
            justify-content: space-around;
            flex: 1;
            margin-left: 10px;
        }
        .goods-desc {
            font-size: 9px;
            text-overflow: ellipsis;
            white-space: nowrap;
            overflow: hidden;
            width: 150px;
        }
        .goods-price {
            color: red;
        }
        .cart-controller {
            display: flex;
            flex-direction: row;
            align-items: center;
        }
        .cart-controller span{
            margin-right: 5px;
        }
        .reduce,.add {
            font-size: 18px;
            color: #2d8cf0;
        }
        .goods-num {
            width: 12px;
            text-align: center;
        }
        .cart-bar {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            height: 42px;
            width: 100%;
            background: #fff;
            align-items: center;
            padding: 5px;
            position: fixed;
            top: 0;
            left: 0;
            z-index: 11;           
        }
        .pay-btn {
            width: 70px;
        }
        .total-price {
            text-align: center;
            flex: 1;
            font-size: 13px;
            color: red;
        }
        .total-price span {
            color: #222;
            font-size: 18px;
            font-weight: bolder;
        }
        .num-badge.gray {
            background: #ccc;
        }
        .slide-fade-enter-active {
          transition: all .1s ease;
        }
        .slide-fade-leave-active {
          transition: all .3s cubic-bezier(1.0, 0.5, 0.8, 1.0);
        }
        .slide-fade-enter, .slide-fade-leave-to {
          transform: translateX(10px);
          opacity: 0;
        }
    </style>
</head>
<body>
    <div id="app">
        <header>
             <Icon type="ios-list" style="margin-left:10px;"></Icon>
             <span>{{pageHead}}</span>
             <Icon type="ios-search" style="margin-right:10px;"></Icon>     
        </header>
        <div class="container">
            <ul class="goods-list">
                                <!-- css3 动画名称 -->
                <transition name="slide-fade" v-for="(goods,index) in goodsList">
                    <li class="goods"  v-if="goods.goods_num">
                        <img :src="goods.goods_thumb" alt="">
                        <div class="goods-content">
                            <p class="goods-title">{{goods.goods_name}}</p>
                            <p class="goods-desc">{{goods.goods_desc}}</p>
                            <p class="goods-price">¥{{goods.goods_price}}</p>
                        </div>
                        <div class="cart-controller">
                            <span class="reduce"  @click="reduceGoods(index)">
                                <Icon type="minus-circled"></Icon>
                            </span>
                            <span class="goods-num">{{goods.goods_num}}</span>
                            <span class="add" @click="addGoods(index)">
                                <Icon type="plus-circled"></Icon>
                            </span>
                        </div>
                    </li>
                </transition>
            </ul>
            <div class="cart-bar">
                <div class="total-price">
                    <span>Total:</span> ¥{{totalPrice}}
                </div>
                <i-button type="success" class="pay-btn" @click="pay(totalPrice)">支付</i-button>    
            </div>
        </div>
        <Modal v-model="modal6" title="提示"  @on-ok="ok" @on-cancel="cancel">
        <p>总价:¥{{totalPrice}}</p>
    </Modal>
        <footer>
            <ul>
                <li>
                    <Icon type="ios-home"></Icon>
                </li>
                <li>
                    <Icon type="ios-chatbubble"></Icon>
                </li>
                <li>
                    <Icon type="ios-cart"></Icon>
                                                            <!--  绑定样式,isGray为true时显示  -->
                    <span class="num-badge"  v-bind:class="{gray:isGray}">{{goodsNum}}</span>
                </li>
                <li>
                    <Icon type="ios-person"></Icon>
                </li>
            </ul>
        </footer>
    </div>
<script>
    new Vue({
        el: '#app',
        data: {
            isGray: false,//默认false
            modal6: false,
            pageHead: "购物车",
            goodsList: [
                {
                    goods_name: "Coca Cola",
                    goods_desc: "可口可乐,made in America",
                    goods_price: "12",
                    goods_thumb: "static/images/cola.jpg",
                    goods_num: 6
                },{
                    goods_name: "女装",
                    goods_desc: "夏日女装",
                    goods_price: "199",
                    goods_thumb: "static/images/clothfamale.jpg",
                    goods_num: 1
                },{
                    goods_name: "macbook 13寸 经典版",
                    goods_desc: "macbook 13寸 经典版,限时打折",
                    goods_price: "6999",
                    goods_thumb: "static/images/mac.jpg",
                    goods_num: 1
                },{
                    goods_name: "青芒果",
                    goods_desc: "深山青芒果",
                    goods_price: "6",
                    goods_thumb: "static/images/mongo.jpg",
                    goods_num: 5
                },{
                    goods_name: "play station 4",
                    goods_desc: "索尼正品认证,限时赠送<<神秘海域4>>",
                    goods_price: "2666",
                    goods_thumb: "static/images/ps4.jpg",
                    goods_num: 1
                },{
                    goods_name: "纯正米酒",
                    goods_desc: "哇哦~~",
                    goods_price: "99",
                    goods_thumb: "static/images/ricewine.jpg",
                    goods_num: 3
                },
            ]
        },
        computed: {
            totalPrice: function(){//计算总价
                var total = 0;
                this.goodsList.forEach(function(item,index){//循环商品列表,单价 x 数量,再加等
                    total += (item.goods_price - 0) * item.goods_num;
                });
                return total
            },
            goodsNum: function(){//加等每个商品种类的数量 
                var num = 0;
                this.goodsList.forEach(function(item,index){
                    num += item.goods_num;
                });
                if(num == 0) {//如果商品总量为0时,this.isGray = true
                    this.isGray = true
                }
                return num
            }
        },
        methods: {
            //v-for="(goods,index) in goodsList" 通过这种方式获取index
            addGoods: function(index){//@click(index),在商品列表数组中传入点击商品的index值,从而改变相应商品的数据
                this.goodsList[index].goods_num ++ ;
            },
            reduceGoods: function(index){//@click(index),在商品列表数组中传入点击商品的index值,从而改变相应商品的数据
                if(this.goodsList[index].goods_num <= 0) {//当商品数量小于或等于0时,利用vue的transition组件包裹单个goods li,做到动画消失
                    this.goodsList.splice(index,1);//也可以在goods----li 标签里利用v-if或者 v-bind:class="{your-animate-class:goods.goods_num}"方式
                    return                         //完全消失后在商品列表中移除该商品         
                }
                this.goodsList[index].goods_num -- ;
            },
            pay: function(){
                this.modal6 = true;//ivew 对话框组件,点击支付显示
            },
            ok: function(){//点击确定,关闭
                    this.modal6 = false;
                    this.$Message.success('支付成功');//iview 消息提示组件
            },
            cancel: function(){
                this.modal6 = false;
                this.$Message.success('取消支付');
            }
        }  
    })
    /**
    * 总结
    * v-bind:class="{classname: variable<-->boolean}"
    * @click="functionname()"绑定函数
    * computed: 计算属性的运用; totalPrice,goodsNum
    * splice(item,0,[]) => 0:增加item或者[]; 1: 删除item
    * v-for="(item,index) in items" => item = self,index = self index
    * v-if="variable" => true or false
    * vue组件transition的运用 naem="animation-name" v-if状态的改变触发动画
    * iview 组件Icon的使用,badge的使用(其中count属性不支持,count="{{ goodsNum }}"的形式 => 也许有解决方案,不行可以自行模拟)
    * iview 组件this.$Message.success(msg)
    *                       .info(msg)
    *                       .error(msg) 
    * iview 组件<Modal v-modal="modalvalue" :loading="loading" @on-ok="ok" @on-cancel="cancel"></Modal> ==> 通过设置modalvalue的值来显隐modal对话框
    * :loading => 是否在确定按钮上使用 loading 动画 title => 设置标题信息 @on-ok="ok" => 点击确定按钮回调函数 @on-cancel="cancel" => 点击取消按钮回调函数
    *  
    * date: 2018-7-14 22:46
    * author: Foresea
    *
    *
    * =====================  待续  =====================       
    */
  </script>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容