走進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