Vue全新技術棧重構黃老師餓了麼商家應用總結

項目倉庫地址: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

項目技術棧

  1. 前端java

    • vue開發項目核心框架
    • axios HTTP請求模塊
    • lib-flexible 移動端屏幕適配方案
    • better-scroll 仿IOS效果的移動端滾動庫
    • normalize.css 第三方css樣式初始化模塊
    • es 6/7 下一代javascript語法
  2. 後端ios

    • express 搭建服務端應用核心框架
  3. 開發git

    • vue-cli 項目初始化腳手架
    • vue-devtools 項目開發環境調試工具
    • vscode chrome git macbookpro
  4. 部署github

應用功能

  • [x] 商品頁web

    • [x] 商品分類導航和商品列表的聯動效果
    • [x] 點擊商品分類菜單展現對應商品列表信息
    • [x] 添加/刪除商品到購物車
    • [x] 點擊商品進入到詳情頁面
    • [ ] 商品添加到購物車動畫效果
    • [ ] 頁面滾動到對應商品類別時的標題吸頂效果
  • [x] 評論頁

    • [x] 綜合評論信息渲染
    • [x] 切換評論篩選項按鈕展現對應的信息
    • [x] 選擇展現是否有內容的評論
  • [x] 商家頁

    • [x] 商家店鋪信息展現
    • [x] 收藏店鋪
    • [x] 商家實景圖片具備bounce效果的滑動顯示
  • [x] 應用頭部

    • [x] 點擊展現詳情
    • [ ] 公告信息動態滾動顯示
  • [x] 購物車

    • [x] 根據商品個數顯示不一樣的狀態
    • [x] 購物車商品列表
    • [x] 支付彈窗
    • [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-scrollscroll事件 API這裏

添加/刪除 商品到購物車

效果截圖

完整代碼 https://github.com/konglingwen94/vue-elm-sell/blob/master/src/components/food-picker/index.vue

思路

添加商品到購物車是一個多場景的功能,因爲這裏的購物車功能是一個多頁面聯動的效果,購物車商品數量的實時更改也須要同步到商品內容頁和商品詳情頁。從功能映射到javascript語言數據結構層面的話,不難想到對象引用傳遞的特色能夠做爲實現此功能的底層架構思路,那就讓咱們去實現它吧。

實現

爲了統計商品的數量。首先須要給每個商品信息對象添加一個默認值爲0count屬性,添加後的對象長這樣

{
  "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,這樣在增長/減小商品數量的時候直接操做foodInfocount屬性來實現同步數據的效果。

/components/food-picker.vue 組件代碼

<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數據驅動視圖改變的思想,熟練的掌握了組件化開發項目的流程,同時也感覺到所帶來的便利,爲本身接下來預備作的中大型項目建築好了橋樑。

支持

若是本項目對您學習有幫助,請您動手點個starhttps://github.com/konglingwen94/vue-elm-sell。也但願您繼續關注個人動態https://github.com/konglingwen94,有了您的支持我會有動力開源更多有趣的項目。

歡迎點贊和留言,謝謝!

相關文章
相關標籤/搜索