您當前位置: 南順網絡>> 官方資訊>> 建站知識

走進Vue時代進階篇(01):重構電商購物車模塊

前言

從這篇文章(zhāng)開始,我準備給大家分享一(yī)些關于Vue.js這門框架的(de)技巧性系列文章(zhāng),正好我們公司項目中也用到了Vue。所以,教是最好的(de)學(xué)。進階篇比較适合于二三線城市,還在小廠打拼的(de)童鞋們。歡迎你們跟着閏土大叔走進MVVM時代。

首先,需要聲明一(yī)點,本篇文章(zhāng)不會從基礎開始講起,因為(wèi)Vue官方文檔已經講得很清楚了,我就不再贅述了。所以,之前對Vue這門框架不太熟悉的(de)童鞋可(kě)以先去(qù)官網上看看基礎知識,比如(rú)Vue的(de)模闆語法、計算屬性、條件渲染、列表渲染、事件處理(lǐ)、表單輸入綁定以及Class與Style綁定等。進階篇我會側重講點官網入門指南沒講到的(de)、偏技巧性的(de)東西。

那麽接下來,搬好小闆凳,正文從這開始~

在開始寫購物車的(de)業務代碼前,我們需要對需求進行分析,這樣有助于我們理(lǐ)清業務邏輯。首先,購物車需要展示一(yī)個已加入購物車的(de)商品列表,包含商品的(de)名稱、單價、購買數量和(hé)操作等信息,還需要實時顯示購買的(de)總價。其中購買數量可(kě)以增加或減少,每類商品還可(kě)以從購物車中移除。最終實現的(de)效果如(rú)下圖所示:

圖片描述

在明确需求之後,我們就可(kě)以開始動手敲代碼了。基礎篇都會以直接引入Vue.js文件為(wèi)例。先在index.html中引入Vue.js,然後創建一(yī)個根元素來挂載Vue實例,在data選項內(nèi)寫入我們需要的(de)數據列表,裏面包含了商品名稱、單價、購買數量。這裏需要說明一(yī)下,在實際業務中,這個列表是通過Ajax從服務端動态獲取的(de),這裏隻做(zuò)示例:

 1 var app = new Vue({
 2       el:'#app',
 3       data:{
 4         list:[
 5           {
 6             id:1,
 7             name:'iphone X',
 8             price:8388,
 9             count:110           },11           {12             id:2,13             name:'apple watch3',14             price:2888,15             count:116           },17           {18             id:3,19             name:'MackBook Pro',20             price:12488,21             count:122           }23         ]24       }25 })

數據構建好之後,我們便可(kě)以在index.html中展示列表了,毫無疑問的(de)是,肯定會用到v-for指令。為(wèi)了考慮到用戶體驗,我們在這裏需要做(zuò)一(yī)點小小的(de)優化。因為(wèi)每個商品都是可(kě)以從購物車删除的(de),所以當列表為(wèi)空時,在頁面顯示一(yī)個“購物車為(wèi)空”的(de)提示會更加友好,我們可(kě)以通過判斷數組list的(de)長(cháng)度來實現該功能:

1 <div id="app" v-clock>
 2     <template v-if="list.length">
 3       <table class="shopCar">
 4         <thead>
 5           <tr>
 6             <th></th>
 7             <th>商品名稱</th>
 8             <th>商品單價</th>
 9             <th>購買數量</th>10             <th>操作</th>11           </tr>
12         </thead>13         <tbody>14           <tr v-for="(item, index) in list">15             <td>{{ index+1 }}</td>16             <td>{{ item.name }}</td>17             <td>{{ item.price }}</td>18             <td>19               <button @click="handleReduce(index)" :disabled="item.count === 1">-</button>20               {{ item.count }}21               <button @click="handleAdd(index)">+</button>22             </td>
23             <td>
24               <button @click="handleRemove(index)">移除</button>25             </td>
26           </tr>27         </tbody>
28       </table>29       <h3>總價:¥ {{ totalPrice }}</h3>30     </template>
31     <div v-else>購物車為(wèi)空</div>32   </div>

Tips: 解決Vue初始化慢導緻頁面閃動的(de)最佳實踐

相信眼尖的(de)同學(xué)會發現一(yī)個比較陌生的(de)指令v-cloak,它究竟是幹嘛的(de)?官網指南裏也沒提到啊...

這裏抖一(yī)個小包袱,論解決Vue初始化慢導緻頁面閃動的(de)最佳實踐。你可(kě)能會發現,當網速較慢、Vue.js文件還沒加載完時,在頁面上會顯示 {{ 插值 }} 的(de)字樣,知道(dào)Vue創建實例、編譯模闆時,DOM才會被替換,所以這個過程屏幕是有閃動的(de)。于是,v-cloak指令應運而生,你隻需要在根元素上添加上這個指令,然後在CSS中添加上一(yī)句:

1 [v-cloak]{2       display:none;3 }

就可(kě)以完美的(de)解決這個問題了。但需要注意的(de)是,v-cloak對于簡單的(de)項目很實用,但是在具有webpack工程化的(de)項目裏,項目的(de)HTML結構隻有一(yī)個空的(de)div元素,剩餘的(de)內(nèi)容都是由路由去(qù)挂載不同組件完成的(de),所以不再需要v-cloak。

讓我們接着說回購物車的(de)事情。總價totalPrice是依賴于商品列表而動态變化的(de),所以我們要考慮用計算屬性來實現,順便将結果轉化為(wèi)帶有“千位分隔符”的(de)數字。

 1 computed:{
 2       totalPrice: function(){
 3             var total = 0;
 4             for(var i=0;i<this.list.length;i++){
 5               var item = this.list[i];
 6               total += item.price * item.count;
 7             }
 8             return total.toString().replace(/\B(?=(\d{3})+$)/g,',');
 9       }10 }

這段代碼的(de)難點在于千位分隔符的(de)轉換(每隔三位數加進一(yī)個逗号),各位童鞋可(kě)以查閱正則匹配的(de)相關內(nèi)容後嘗試了解replace()的(de)正則含義。

最後就剩下商品列表的(de)渲染和(hé)相關的(de)幾個操作了。先是用v-for指令把數組list循環出來。商品序号、名稱、單價、數量都是直接使用插值來完成的(de),在第4列的(de)兩個按鈕<button>用于增減購買數量,分别綁定了兩個方法handleReduce和(hé)handleAdd,參數都是當前商品在數組list 中的(de)索引。button中使用了v-bind和(hé)v-on兩個指令(這裏用的(de)都是語法糖寫法)。

Tips: 什麽是語法糖

語法糖就是指在不影響功能的(de)情況下,添加了某種方法實現同樣的(de)效果。

讓我們接着說回button綁定的(de)動态屬性disabled,每件商品購買數量最少是1件,所以當count為(wèi)1時,不允許再繼續減少,所以這裏給<button>動态綁定了disabled特性來禁用按鈕。

最後就是在methods選項內(nèi)添加3個方法:

 1 methods:{
 2         handleReduce: function(index){
 3           if(this.list[index].count === 1) return;
 4           this.list[index].count--;
 5         },
 6         handleAdd: function(index){
 7           this.list[index].count++;
 8         },
 9         handleRemove: function(index){10           this.list.splice(index, 1);11         }12 }

這3個方法都是直接對數組list的(de)操作,沒有太複雜的(de)邏輯。需要說明的(de)是,雖然在button上已經綁定了disabled特性,但是在handleReduce方法內(nèi)又判斷了一(yī)遍。這是因為(wèi)在某些時候,可(kě)能不一(yī)定會用button标簽,也可(kě)能是div、span等,給它們增加disabled是沒有任何作用的(de),所以為(wèi)了安全起見,在業務邏輯中再判斷一(yī)次,避免因修改HTML模闆後出現bug。

後記

這大概就是一(yī)次用Vue重構電商項目中的(de)購物車模塊的(de)所有實現過程。這可(kě)能是你們學(xué)習Vue.js框架的(de)一(yī)小步,卻是我當Vue講師夢想邁出的(de)一(yī)大步。


編輯:--ns868