1. 程式人生 > >5.goods商品列表頁開發

5.goods商品列表頁開發

dex eve ren 寬度 nth 購物車 區間 let scrollto

goods組件顯示的區域是固定的,也沒有滾動條,所以是采用絕對布局的,左右分為menu欄和foods欄,左邊固定布局,右邊自適應布局,采用flex布局。

技術分享

寫CSS樣式的時候,盡量用class,少用tag,因為class的查找效率優於tag,尤其是嵌套層級比較多的時候。左邊的menu欄有些是一行有些是多行,要做到不管單行還是多行都是垂直是居中,可以用display:table,table布局是實現垂直居中的有效布局。menu-item設置display:table,text設置display:table-cell,vertical-align:center

<ul>
<li v-for="(item, index) in goods" class="menu-item" :class="{‘current‘:currentIndex===index}" @click="selectMenu(index, $event)">
<span class="text border-1px">
  <span v-show="item.type>0" class="icon" :class="classMap[item.type]"></span>
  {{item.name}}
</span>
</li>
</ul>

右邊的food欄用兩個<ul v-for="XXX">來實現遍歷

每個食品的顯示分為左邊icon和右邊的content,用flex布局來實現,左邊固定寬度,右邊自適應布局。goods組件的右邊的food欄,除了最後一個食品的下面都有1px的border,要去掉最後一個食品的border,課程中是在mixin中寫了一個border-none()的樣式,把after的偽類設置為display:none。也可以用另一種方式來實現,由於border是通過after偽類來實現的,那麽如果給最後一個食品的after偽類設置為border:none應該就可以去掉border了。

技術分享

border-none()
&:after
display: none

food-item設置了18px的margin,但是由於相鄰兩個food-item的上下margin是會重合的,所以要再設置一個padding-bottom,但是最後一個food-item就會有一個18px的margin-bottom和18px的padding-bottom,所以最後一個fodd-tiem的margin-bottom要設置為0。

.food-item
display: flex
margin: 18px
padding-bottom: 18px
border-1px(rgba(7, 17, 27, 0.1))

用better scroll庫實現滾動效果, new BScroll()有兩個參數,第一個是dom對象,第二個是可選對象。給dom對象增加ref屬性,<div class="foods-wrapper" ref="menuWrapper">,在js中用this.$refs獲取dom對象,this.meunScroll = new BScroll(this.$refs.menuWrapper, {});

DOM對象是異步更新的,所以要把滾動的初始化函數放在¥nextTick()函數中,$nextTick 是在下次 DOM 更新循環結束之後執行延遲回調,在修改數據之後使用 $nextTick,則可以在回調中獲取更新後的 DOM。

要實現左邊的menu和右邊的food的連動,要計算出右邊每一個類的food的高度區間,用getElementsByClassNames獲取每一個類food的DOM對象,用函數clientHeight得到的DOM對象的高度。

_calculateHeight() {
let foodList = this.$refs.foodsWrapper.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);
}

}

然後拿到實時的y值與高度區間值對比,在BScroll函數中傳入參數probeType:3就可以獲取實時滾動的位置,用this.foodsscroll.on()監聽滾動事件

this.foodsScroll = new BScroll(this.$refs.foodsWrapper, {
click: true,
probeType: 3
});
this.foodsScroll.on(‘scroll‘, (pos) => {
this.scrollY = Math.abs(Math.round(pos.y));
});
},

當food欄滾動時,獲取當前的坐標,與區間對比,得到對應的index,更新左邊的menu欄,對應index的menu-item會獲得一個current的class。用better Scroll之後,點擊時會有兩個事件,一個是瀏覽器原生事件,一個是better Scroll派發的時間,其中瀏覽器原生事件都沒有_constructed屬性,better scroll派發的事件有_constructed屬性。

<li v-for="(item, index) in goods" class="menu-item" :class="{‘current‘:currentIndex===index}" @click="selectMenu(index, $event)">

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;
}
}

點擊左邊的menu列表時,根據index,通過scrollToElement把右邊的列表滾動到對應的位置

selectMenu(index, event) {
if (!event._constructed) {
return;
}
let foodList = this.$refs.foodsWrapper.getElementsByClassName(‘food-list-hook‘);
let el = foodList[index];
this.foodsScroll.scrollToElement(el, 300);
},

購物車組件開發

5.goods商品列表頁開發