用vue實現一個淘寶購物車,給和我同樣苦苦掙扎的前端小白(更新)

最近後端的同事要我寫一個購物車,一開始我用jQuery寫,但寫着寫着發現邏輯太混亂了,寫不下去。最後花了五分鐘找了個demo丟給了他。後來我不甘心,畢竟水平菜還不求上進就完蛋了。因此我想着用vue來實現一個。javascript

原本想看看別人的代碼,但搜索了下github發現,能找到的購物車都是兩級分類的。而京東、淘寶之流都是三級分類的:  
1. 全選        
2. 店鋪全選  
3. 商品選中

這樣的貌似纔有實用價值css

html部分,不過多贅述

<div id="cart">
    <section class="cartMain">
        <div class="cartMain_hd">
            <ul class="order_lists cartTop">
                <li class="list_chk">
                    <!--全部商品全選-->
                    <input type="checkbox" id="all" class="whole_check">
                    <label for="all" :class="fetchData.status?'mark':''" @click="cartchoose()"></label>
                    全選
                </li>
                <li class="list_con">商品信息</li>
                <li class="list_info">商品參數</li>
                <li class="list_price">單價</li>
                <li class="list_amount">數量</li>
                <li class="list_sum">金額</li>
                <li class="list_op">操做</li>
               
            </ul>
        </div>

         <div class="cartBox" v-for="item in fetchData.list" key="index">
            <div class="shop_info">
                <div class="all_check">
                    <input type="checkbox" id="shop_a" class="shopChoice">
                    <label for="shop_a" class="shop" :class="item.check?'mark':''" @click="shopchoose(item)"></label>
                </div>
                <div class="shop_name">
                    店鋪:<a href="javascript:;">{{item.shop_name}}</a>
                </div>
            </div>
            <div class="order_content">
                <ul class="order_lists" v-for="pro in item.products">
                    <li class="list_chk">
                        <input type="checkbox" id="checkbox_2" class="son_check">
                        <label for="checkbox_2" :class="pro.checked?'mark':''" @click="choose(item,pro)"></label>
                    </li>
                    <li class="list_con">
                        <div class="list_img"><a href="javascript:;"><img :src="pro.img" alt=""></a></div>
                        <div class="list_text"><a href="javascript:;">{{pro.text}}</a>
                        <span class="list_custom">定製</span>
                        </div>
                    </li>
                    <li class="list_info">
                        <p>規格:默認</p>
                        <p>尺寸:16*16*3(cm)</p>
                    </li>
                    <li class="list_price">
                        <p class="price">¥{{pro.price}}</p>
                        <div class="charge">
                            <p>更多促銷</p>
                            <div class="chargebox">
                                測試
                            </div>
                        </div>
                    </li>
                    <li class="list_amount">
                        <div class="amount_box">
                            <a href="javascript:;" class="reduce reSty" @click="reduce(pro)">-</a>
                            <input type="text" v-model="pro.num" class="sum">
                            <a href="javascript:;" class="plus" @click="add(pro)">+</a>
                        </div>
                    </li>
                    <li class="list_sum">
                        <p class="sum_price">¥{{pro.sum}}</p>
                    </li>
                    <li class="list_op">
                        <p class="collect"><a href="javascript:;" class="colBtn">收藏商品</a></p>
                        <p class="del"><a href="javascript:;" class="delBtn">移除商品</a></p>
                        <p class="custom"><a href="javascript:;" class="cusBtn">定製商品</a></p>
                        <div class="custombox">
                                測試
                        </div>
                    </li>
                </ul>
            </div>
        </div> 

        
        
        <!--底部-->
        <div class="bar-wrapper">
            <div class="bar-right">
                <div class="piece">已選商品<strong class="piece_num">{{this.fetchData.allnum}}</strong>件</div>
                <div class="totalMoney">共計: <strong class="total_text">¥{{this.fetchData.allsum}}</strong></div>
                <div class="calBtn"><a href="javascript:;">結算</a></div>
            </div>
        </div>
    </section>
    <section class="model_bg"></section>
    <section class="my_model">
        <p class="title">刪除寶貝<span class="closeModel">X</span></p>
        <p>您確認要刪除該寶貝嗎?</p>
        <div class="opBtn"><a href="javascript:;" class="dialog-sure">肯定</a><a href="javascript:;" class="dialog-close">關閉</a></div>
    </section>
    </div>

圖片描述

大概長這個樣子,很普通的一個購物車頁面,另外html和css部分不是我寫的,是下載的jQuery購物車的demo裏的代碼,這樣比較省事情。html

購物車邏輯分析

1.三級選中按鈕的實現
2.每件商品總價的變更
3.商品總件數、商品總計價格的變更
4.輸入商品數量致使2,3的變更(未實現)vue

先上數據

data(){
                return{
                    fetchData:{
                        list:[
                            {
                                shop_id:1,
                                shop_name:'搜獵人藝術生活',
                                products:[
                                    {
                                        pro_id:101,
                                        text:'洗面奶洗面奶洗面奶洗面奶洗面奶洗面奶洗面奶洗面奶',
                                        price:480,
                                        num:1,
                                        img:'./images/1.png',
                                        sum:480,
                                        checked:false//商品選中狀態
                                    },
                                    {
                                        pro_id:102,
                                        text:'花露水花露水花露水花露水花露水花露水花露水花露水',
                                        price:680,
                                        num:1,
                                        img:'./images/2.png',
                                        sum:680,
                                        checked:false
                                    },
                                    {
                                        pro_id:103,
                                        text:'燕麥片燕麥片燕麥片燕麥片燕麥片燕麥片燕麥片燕麥片',
                                        price:380,
                                        num:1,
                                        img:'./images/3.png',
                                        sum:380,
                                        checked:false
                                    }
                                ],
                                check:false,//店鋪選中狀態
                                choose:0,//商品選中個數
                            },
                            {
                                shop_id:2,
                                shop_name:'卷卷旗艦店',
                                products:[
                                    {
                                        pro_id:201,
                                        text:'剃鬚刀剃鬚刀剃鬚刀剃鬚刀剃鬚刀剃鬚刀剃鬚刀剃鬚刀',
                                        price:580,
                                        num:1,
                                        img:'./images/4.png',
                                        sum:580,
                                        checked:false
                                    },
                                    {
                                        pro_id:202,
                                        text:'衛生紙衛生紙衛生紙衛生紙衛生紙衛生紙衛生紙衛生紙',
                                        price:780,
                                        num:1,
                                        img:'./images/5.png',
                                        sum:780,
                                        checked:false
                                    }
                                ],
                                check:false,
                                choose:0,
                            },
                            {
                                shop_id:3,
                                shop_name:'瓜皮的神祕商店',
                                products:[
                                    {
                                        pro_id:301,
                                        text:'眼鏡片眼鏡片眼鏡片眼鏡片眼鏡片眼鏡片眼鏡片眼鏡片',
                                        price:180,
                                        num:1,
                                        img:'./images/6.png',
                                        sum:180,
                                        checked:false
                                    },
                                    {
                                        pro_id:302,
                                        text:'湊數的湊數的湊數的湊數的湊數的湊數的湊數的湊數的',
                                        price:280,
                                        num:1,
                                        img:'./images/7.png',
                                        sum:280,
                                        checked:false
                                    }                                
                                ],
                                check:false,
                                choose:0,
                            }
                        ],
                    status:false,//全選選中狀態
                    allchoose:0,//店鋪選中個數
                    allsum:0,//總計價格
                    allnum:0//總計數量
                    }
                }
            },

意義不明的部分寫了註釋,其餘數據一目瞭然java

單個商品的選中按鈕

單個商品的選中按鈕很容易實現,通常是添加一個點擊方法,值取反。但在購物車中這樣的方法是不行的,單個商品的選中以及取消所執行的邏輯有部分不一樣,因此我選擇將其拆分。git

choosetrue(item,pro){
                    pro.checked=true//將商品選中狀態改成true
                    ++item.choose===item.products.length?item.check=true:''//這裏執行了兩部,選中商品數量先+1,再與該店鋪商品數量比較,若是相等就更改店鋪選中狀態爲true
                    item.check?++this.fetchData.allchoose===this.fetchData.list.length?this.fetchData.status=true:this.fetchData.status=false:''//若是店鋪選中狀態改成true,選中店鋪數量先+1,再與店鋪數量比較,若是相等就更改全選選中狀態爲true      
                },
choosefalse(item,pro){
                    pro.checked=false//將商品選中狀態改成false
                    --item.choose//選中商品數量-1
                    if(item.check){//若是店鋪是被選中的,更改店鋪選中狀態
                        item.check=false
                        --this.fetchData.allchoose//而且選中店鋪數量-1
                    }
                    this.fetchData.status=false//不管以前全選的狀態,將其改成false就行
                },
choose(item,pro){
                    !pro.checked?this.choosetrue(item,pro):this.choosefalse(item,pro)
                },//這裏是綁定到html上的方法,取反是因爲你在觸發方法的時候取的是以前的狀態

相信有的人看了代碼仍是以爲能把三個函數寫在一塊兒,其實我以前就是這麼幹的,而後就悲劇了,多是我功底不夠。先無論這些。如今分析下店鋪全選的邏輯:github

  1. 選中以後,店鋪下的全部商品選中,而且判斷全選按鈕是否要選中後端

  2. 取消選中,店鋪下的全部商品取消選中app

這是基本邏輯,但若是照這個思路寫,用循環將商品狀態更改,很輕鬆,可是仍是須要判斷是否要選中全選按鈕。咱們換個思路吧,由於我發現「判斷是否要選中全選按鈕」已經在以前寫過了。店鋪選中按鈕的前半部分邏輯其實就是choosetrue函數執行了必定的次數,我是這樣寫的:函數

單個店鋪的選中按鈕

shoptrue(item){
                    item.products.forEach((pro)=>{
                        pro.checked===false?this.choosetrue(item,pro):''
                    })
                },//循環店鋪中的商品,先篩選出目前沒選中的商品,給它執行choosetrue函數
shopfalse(item){
                    item.products.forEach((pro)=>{
                        pro.checked===true?this.choosefalse(item,pro):''
                    })
                },//循環店鋪中的商品,先篩選出目前被選中的商品,給它執行choosefalse函數
shopchoose(item){
                    !item.check?this.shoptrue(item):this.shopfalse(item)
                },

剛纔分開寫的好處就出現啦,至於爲何要篩選一下,這和以後計算商品總價有關係(若是隻是寫多選按鈕的邏輯,有人會圖方便不篩選,好比一小時以前的我)

全選按鈕

cartchoose(){
                    this.fetchData.status=!this.fetchData.status//取反改變狀態
                    this.fetchData.status?this.fetchData.list.forEach((item)=>this.shoptrue(item)):this.fetchData.list.forEach((item)=>this.shopfalse(item))
                },//根據取反後的狀態進行相應的店鋪按鈕操做

有人可能發現爲何全選不進行篩選,實際上是不須要篩選。以前選中的店鋪按鈕下的商品狀態必然所有是true,只是空跑了一遍,總結起來的邏輯是:沒選中的店鋪改變狀態->沒選中的商品改變狀態

增長按鈕&減小按鈕

add(pro){
                    pro.num++//商品數量+1
                    pro.sum+=pro.price//商品總價變更
                   
                },
reduce(pro){
                    if(pro.num===1){
                        pro.num//當商品數量=1,不變
                    }else{
                        pro.num--//不然-1
                        pro.sum-=pro.price//商品總價變更
                     
                    }
                }

這裏的邏輯比較簡單,不細說。
接下來就是商品總計價格的變更,這裏又要分析一下:首先,選中的商品纔會影響總計價格的變更,那咱們只須要將邏輯寫着choosetrue函數中就行,而不須要去一遍一遍循環選中商品的總價格去計算總計價格,稍微調整下。

choosetrue(item,pro){
                    pro.checked=true
                    ++item.choose===item.products.length?item.check=true:''
                    item.check?++this.fetchData.allchoose===this.fetchData.list.length?this.fetchData.status=true:this.fetchData.status=false:''
                    this.fetchData.allsum+=pro.sum//當觸發商品選中按鈕,將商品總價格添加到總計價格
                },
choosefalse(item,pro){
                    pro.checked=false
                    --item.choose
                    if(item.check){
                        item.check=false
                        --this.fetchData.allchoose
                    }
                    this.fetchData.status=false
                    this.fetchData.allsum-=pro.sum//當觸發商品取消按鈕,將商品總價格從總計價格刪去                 
                },
add(pro){
                    pro.num++
                    pro.sum+=pro.price
                    pro.checked?this.fetchData.allsum+=pro.price:this.fetchData.allsum//這裏判斷下商品的狀態決定是否是要改變總計價格
                },
reduce(pro){
                    if(pro.num===1){
                        pro.num
                    }else{
                        pro.num--
                        pro.sum-=pro.price
                        pro.checked?this.fetchData.allsum-=pro.price:this.fetchData.allsum//同上
                    }
                }

未完成部分

商品數量的計算,這個淘寶和京東對數量的計算不一樣,淘寶是商品種類的數量,京東是商品總件數量,邏輯也較簡單,跟商品價格後面相應添加就行。
當手動輸入商品數量時,價格隨之變更,我思考了半天只想到數據監測,但數據嵌套太深了,若是監測fetchData,監測函數會屢次無心義觸發,監測鍵盤也不現實,最好的辦法是監測num這個數據,但我沒繼續實驗,對watch用的不太熟。有小夥伴有實現方法麻煩告知

更新

以前全部未完成部分已經解決,小夥伴們能夠去github看源碼。主要包括(商品數量計算,監控輸入數字引發價格變更,輸入數字的各類限制,避免有人填寫負數和小數之類的)

源碼

https://github.com/yuyeqianxu...

有bug麻煩告知一聲,謝謝

相關文章
相關標籤/搜索