一、專案展示:
注意:如果gif動態圖看不了,麻煩大家點選github美團專案中mt-app/src/assets/美團.gif便可以觀看!
本專案很適合vue初學者,如果業務邏輯看不懂,很歡迎一起討論!
原始碼地址:mt-app,歡迎 star 和 fork
如果對你有些許幫助,不妨點贊、關注我一下啊
二、專案涉及到技術棧:
- vue全家桶:Vue、Vue-router、Vue-cli等
- 元件化:單Vue檔案
- 模組化:ES6 Module
- 第三方模組:better-scroll axios等
- 基礎開發環境和包管理:Node、npm
- 構建工具:webpack
- 編輯器:webstrom
三、專案主要功能
一言而蔽之:一款集點菜、使用者評價和商家資訊為一體的移動端點餐APP
- 點餐頁面 點選商品後自動新增到購物車,並計算好總價,在商品列表、購物車列表和商品詳情頁都可以隨意增減數目,此外左側商品分類和右側的商品相互關聯,通過better-scroll外掛滑動商品列表時,相應的商品分類也會跟著跳轉。
- 使用者評價頁面 主要包括一個TAB欄,包括三部分:全部、有圖和評價三個模組
- 商家資訊頁面 主要介紹一些商家基本資訊,可以通過better-scroll外掛,進行左右滑動圖片
四、專案難點
該專案業務邏輯主要集中在點餐模組,而點餐模組中難點便是如何實現商品列表滑動,以及右側商品分類和左側商品列表如何聯動?
首先要實現商品列表的滑動,就需要用到一個better-scroll外掛,better-scroll 是一款重點解決移動端(已支援 PC)各種滾動場景需求的外掛。
- 安裝better-scroll
npm install better-scroll --save
- 在Good.vue檔案中script引入
import BScroll from 'better-scroll'
這些準備工作做好後,實現左右兩邊列表聯動,總結起來有以下四個步驟: 1. 計算商品分類的區間高度
//template部分
<!--商品列表-->
<div class="foods-wrapper" ref="foodScroll">
<ul>
<!--專場-->
<li class="container-list food-list-hook">
<div v-for="(item,index) in container.operation_source_list" :key="index">
<img :src="item.pic_url">
</div>
</li>
<!-- 具體分類 -->
<li v-for="(item,index) in goods" :key="index" class="food-list food-list-hook">
<h3 class="title">{{item.name}}</h3>
<!-- 具體的商品列表 -->
<ul>
<li v-for="(food,index) in item.spus" :key="index" @click="showDetail(food)" class="food-item">
......
複製程式碼
//JS部分
methods:{
calculateHeight() { // 計算分類的區間總高度(包括專場和所有具體分類的總高)
let foodlist = this.$refs.foodScroll.getElementsByClassName("food-list-hook")
let height = 0
this.listHeight.push(height)
for (let i = 0; i < foodlist.length; i++) {
let item = foodlist[i]
height += item.clientHeight // 累加
this.listHeight.push(height)
}
console.log(this.listHeight)//[0, 43, 1231, 2401, 3589, 4451, 6121, 7656, 8497, 9344, 10080]
},
initScroll() {
this.menuScroll = new BScroll(this.$refs.menuScroll, { //例項化
click: true //點選事件才能生效
})
this.foodScroll = new BScroll(this.$refs.foodScroll, {
probeType: 3,
click: true
})
},
created() {
fetch("/api/goods")
.then(res => res.json())
.then(response => {
if (response.code == 0) {
this.container = response.data.container_operation_source
this.goods = response.data.food_spu_tags
this.poiInfo = response.data.poi_info
this.$nextTick(() => { //在created中資料雖已初始化,但dom未生成,頁面還沒顯示,要使用回撥函式,確保DOM已經更新
this.initScroll() // 執行滾動方法
this.calculateHeight() //呼叫計算分類區間高度的方法
})
}
})
}
複製程式碼
2. 監聽滾動的位置
initScroll() {
this.menuScroll = new BScroll(this.$refs.menuScroll)
this.foodScroll = new BScroll(this.$refs.foodScroll, {
probeType: 3,//在螢幕滑動的過程中實時派發 scroll 事件
click:true//點選事件才能生效
})
//foodScroll監聽事件
this.foodScroll.on("scroll", (pos) => {
this.scrollY = Math.abs(pos.y)
console.log(this.scrollY)
})
}
複製程式碼
3. 根據滾動位置確認下標,與左側對應
computed:{
currentIndex(){
for(let i = 0; i < this.listHeight.length; i++){
let height1 = this.listHeight[i]
let height2 = this.listHeight[i+1] // 獲取商品區間的範圍
if(!height2 || (this.scrollY >= height1 && this.scrollY < height2)){
return i; // 是否在上述區間中
}
}
return 0
}
複製程式碼
<li class="menu-item"
:class="{'current':currentIndex === 0}"//動態繫結一個樣式,.current設定樣式
@click="selectMenu(0)">
<p class="text">
<img class="icon" :src="container.tag_icon" v-if="container.tag_icon">
{{container.tag_name}}
</p>
</li>
<li class="menu-item"
:class="{'current':currentIndex === index + 1}"
v-for="(item,index) in goods" :key="index"
@click="selectMenu(index+1)"
>
複製程式碼
4. 通過下標實現點選左側,滾動右側
<li class="menu-item" :class="{'current':currentIndex===0}" @click="selectMenu(0)">
<li class="menu-item" :class="{'current':currentIndex===index+1}"
v-for="(item,index) in goods" :key="index" @click="selectMenu(index+1)">//同一個函式傳值不一樣
複製程式碼
selectMenu(index) {
let foodlist = this.$refs.foodScroll.getElementsByClassName("food-list-hook")
let element = foodlist[index]
this.foodScroll.scrollToElement(element, 250)
}
複製程式碼
五、專案總結
- vue資料和檢視的分離,以資料驅動檢視,只關心資料變化,DOM操作被封裝,在實際開發過程中大大提高了效率。
- Vue的元件化功能可謂是它的一大亮點,通過將頁面上某一元件的html、CSS、JS程式碼放入一個.vue的檔案中進行管理可以大大提高程式碼的維護性。
- 專案中未做移動端適配,在不同螢幕手機上開啟,可能使用者體驗會差些