項目倉庫地址:https://github.com/konglingwen94/vue-elm-selljavascript
項目線上地址: http://123.56.124.33:5000css
自從學習了Vue
後,能用Vue
解決的場景用例最終我都儘量的用Vue
去實現。單純的用例需求並無完整的項目開發流程,從中能學到的東西也是有限的。在這以前除了使用Vue
作過vue-music的移動端音樂播放器項目和vue-bytedanceJob(重構某獨角獸互聯網公司官方招聘網站)以外,本身並無用Vue
涉獵web
端更復雜的業務場景。html
爲了找一個項目練習,我去github
上開始了搜索,當看到https://github.com/ustbhuangyi/vue-sell
這個項目時,感受這個移動端應用的一些業務場景是本身沒有接觸過的,因而我就照着這個應用的UI
和功能
用本身的知識體系和技術棧進行了重構,大概不到半個月的時間,我完成了第一個commit
提交到項目上線運行,本篇文章就從應用功能和技術實現一些方面剖析此項目的開發過程以及採到的坑。前端
<img src="https://user-gold-cdn.xitu.io/2020/7/1/17308b5c66a54ae5?w=286&h=500&f=gif&s=1854225" width="200">
<img src="https://user-gold-cdn.xitu.io/2020/7/1/17308b647f0cba7f?w=286&h=500&f=gif&s=838667" width="200">
<img src="https://user-gold-cdn.xitu.io/2020/7/1/17308b6220974f7e?w=286&h=500&f=gif&s=1786516" width="200">
<img src="https://user-gold-cdn.xitu.io/2020/7/1/17308b316156fd95?w=286&h=500&f=gif&s=954705" width="200">
<img src="https://user-gold-cdn.xitu.io/2020/7/1/17308b33d9cb205e?w=286&h=500&f=gif&s=1187009" width="200">vue
前端java
vue
開發項目核心框架axios
HTTP請求模塊lib-flexible
移動端屏幕適配方案better-scroll
仿IOS
效果的移動端滾動庫normalize.css
第三方css
樣式初始化模塊es 6/7
下一代javascript
語法後端ios
express
搭建服務端應用核心框架開發git
vue-cli
項目初始化腳手架vue-devtools
項目開發環境調試工具vscode
chrome
git
macbookpro
部署github
[x] 商品頁web
[x] 評論頁
是否有內容的評論
[x] 商家頁
bounce
效果的滑動顯示[x] 應用頭部
[x] 購物車
bounce效果
是指在應用中頁面位置滾動到一個端點繼續滑動時出現反彈的效果,常見場景是IOS
系統應用滑動效果
完整的組件代碼點 https://github.com/konglingwen94/vue-elm-sell/blob/master/src/views/goods/index.vue。
因爲商品導航和內容是兩個獨立的滾動容器,當滾動到一個目標內容塊時怎麼才能激活它所關聯的導航項呢?咱們知道導航項列表和內容列表在排列順序上是一致的,若是能計算出內容滾動位置處在對應區間塊的索引,也就獲得了導航列表應該激活的目標索引,而後就能夠用Vue
數據驅動視圖的思想去實現這一切。
容器的左右聯動效果是指容器滾動到目標內容時激活其關聯的導航菜單項並滾動到可視區域。
找到要激活的目標導航項索引的第一步須要把商品內容的各個類別塊在容器內的縱座標位置存儲起來(給以後找到激活的目標索引提供比較對象),因爲列表內容時動態渲染的,因此這裏須要等全部數據已經渲染完成後才能操做,下面直接看代碼演示吧!
template
部分
<template> /* 這裏只顯示部分代碼*/ <ul class="foods-list"> <li ref="foodsGroup" class="foods-group" v-for="(item,index) in data" :key="index"> <dl class="foods-group-wrapper"> <dt :class="{fixed:currentIndex===index}" class="foods-group-name">{{item.name}}</dt> <dd class="foods-group-item" v-for="(food ,key) in item.foods" :key="key" > {{food.name}} </dd> </dl> </li> </ul> </template>
script
部分
export default { data(){ return { currentIndex: 0,//導航項激活的索引 currentFood: {}, data:[], sectionHeight: [0],//第一個高度塊座標`y`值爲`0` // 渲染完成後的值爲 `[0,1281,1459,1612,2000,2270,2565,2952,3574,4436]` } }, created() { request .get("/goods") .then(response => { this.data = response; }) .then(() => { setTimeout(() => { const sections = this.$refs.foodsGroup; sections.reduce((prevTotal, current) => { const sectionHeight = prevTotal + current.clientHeight; this.sectionHeight.push(sectionHeight); return sectionHeight; }, 0); }); }); } }
有了各個商品塊的y
座標,下一步就須要註冊容器元素的滾動事件了,在回調函數裏經過找到實時滾動位置disanceY
處在sectionHeight
數組中兩個相鄰元素之間的位置從而就獲得了待激活導航索引currentIndex
的值,具體代碼實現以下
<template> <div> <!--導航菜單--> <scroll class="menu"> <ul class="menu-list"> <li @tap="selectMenu(index)" class="menu-item" :class="{selected:currentIndex===index}" v-for="(item,index) in data" :key="index" > <span>{{ item.name}}</span> </li> </ul> </scroll> <!--商品內容--> <scroll ref="foodsScroll" @scroll="onFoodScroll" class="foods"> <!--這裏省略商品內容模板的代碼--> </scroll> </div> </template>
export default { // 這裏省略其餘代碼 methods:{ onFoodScroll({ x, y }) { const distanceY = Math.abs(Math.round(y)); for (let index = 0; index < this.sectionHeight.length; index++) { if ( distanceY >= this.sectionHeight[index] && distanceY < this.sectionHeight[index + 1] ) { this.currentIndex = index; } } } } }
完整的組件代碼點 https://github.com/konglingwen94/vue-elm-sell/blob/master/src/views/goods/index.vue。因爲左右兩側的佈局容器都是基於better-scroll
實現的頁面滾動,因此這裏須要偵聽better-scroll
提供的scroll
事件而不是瀏覽器原生的滾動事件。查看better-scroll
的scroll
事件API
點 這裏。
完整代碼 https://github.com/konglingwen94/vue-elm-sell/blob/master/src/components/food-picker/index.vue
添加商品到購物車是一個多場景的功能,因爲這裏的購物車功能是一個多頁面聯動的效果,購物車商品數量的實時更改也須要同步到商品內容頁和商品詳情頁。從功能映射到javascript
語言數據結構層面的話,不難想到對象引用傳遞的特色能夠做爲實現此功能的底層架構思路,那就讓咱們去實現它吧。
爲了統計商品的數量。首先須要給每個商品信息對象添加一個默認值爲0
的count
屬性,添加後的對象長這樣
{ "count": 0, // 此變量用來存儲添加到購物車的數量 "name": "皮蛋瘦肉粥", "price": 10, "oldPrice": "", "description": "鹹粥", "sellCount": 229, "rating": 100, "info": "一碗皮蛋瘦肉粥,老是我到粥店時的不二之選。香濃軟滑,飽腹暖心,皮蛋的Q彈與瘦肉的滑嫩伴着粥香溢於滿口,讓人喝這樣的一碗粥也以爲心滿意足", "ratings": [ { "username": "3******b", "rateTime": 1469261964000, "rateType": 1, "text": "", "avatar": "http://static.galileo.xiaojukeji.com/static/tms/default_header.png" } ], "icon": "http://fuss10.elemecdn.com/c/cd/c12745ed8a5171e13b427dbc39401jpeg.jpeg?imageView2/1/w/114/h/114", "image": "http://fuss10.elemecdn.com/c/cd/c12745ed8a5171e13b427dbc39401jpeg.jpeg?imageView2/1/w/750/h/750" }
因爲每個商品項都有一個添加到購物車的數量選擇器功能,這樣咱們直接給商品數量選擇器組件設計一個名爲foodInfo
的對象類型props
,這樣在增長/減小商品數量的時候直接操做foodInfo
的count
屬性來實現同步數據的效果。
<template> <div class="food-picker" @click.stop> <div class="reduce-wrapper" @click="reduce"> <i class="iconfont reduce"></i> </div> <div class="counter">{{foodInfo.count}}</div> <div class="add-wrapper" @click="add"> <i class="iconfont add"></i> </div> </div> </template> <script> export default { name: "food-picker", props: { foodInfo: { type: Object, default: () => ({}) } }, methods: { reduce() { if (parseInt(this.foodInfo.count) > 0) { this.foodInfo.count--; } }, add() { this.foodInfo.count++; } } }; </script> <style lang="less" scoped> .food-picker { min-width: 180px; max-width: 200px; display: flex; align-items: center; width: 100%; justify-content: space-between; .iconfont { color: #00a0dc; font-size: 38px; } .counter { // margin: 0 20px; } } </style>
基於目前已經實現的功能,整個應用的數據都是以json
文件的格式存儲在服務器,服務端並無能夠用來增刪改查的API
接口可供使用。下一步我計劃作出管理後臺和服務端API
用來管理前端頁面的數據,使全部模塊的數據都是可配置的,這樣前端所渲染出來的數據也都是動態的,可以整合三端到一個項目也知足了當下Web
全棧開發的場景須要。
經過真實的開發這樣一個複雜交互的應用,本身對Vue
在實際業務場景中的使用和理解有深刻了一步。深刻理解了Vue
的數據驅動視圖改變的思想,熟練的掌握了組件化開發項目的流程,同時也感覺到所帶來的便利,爲本身接下來預備作的中大型項目建築好了橋樑。
若是本項目對您學習有幫助,請您動手點個star
https://github.com/konglingwen94/vue-elm-sell。也但願您繼續關注個人動態https://github.com/konglingwen94,有了您的支持我會有動力開源更多有趣的項目。
歡迎點贊和留言,謝謝!