在大多數(shù)電商場(chǎng)景中,頁(yè)面都會(huì)有類(lèi)目切換加上商品列表的部分,頁(yè)面大概會(huì)長(zhǎng)這樣
創(chuàng)新互聯(lián)主要從事成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)淄博,十余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專(zhuān)業(yè),歡迎來(lái)電咨詢(xún)建站服務(wù):18980820575
每次寫(xiě)類(lèi)似場(chǎng)景的時(shí)候,都需要去為類(lèi)目商品列表寫(xiě)很多邏輯,為了提高開(kāi)發(fā)效率我決定將這一部分抽離成組件。
實(shí)現(xiàn)
1.樣式
所有tab欄的樣式和商品列表的樣式都提供插槽,供業(yè)務(wù)自己定制
2.變量
isTabFixed: false,//是否吸頂 tab: 1,//當(dāng)前tab page: 1,//當(dāng)前頁(yè)數(shù) listStatus: { finished: false,//是否已是最后一頁(yè) loading: false,//是否加載中 }, items: [],//商品數(shù)組 tabMap: [],//tab列表數(shù)組 cache:{},//緩存 listName: '',//商品列表名稱(chēng) tabName: '',//tab列表名稱(chēng) apiName: '',//api方法名稱(chēng) queryName: '',//api請(qǐng)求參數(shù)名稱(chēng)
3.緩存設(shè)計(jì)
為了減少消耗,已經(jīng)請(qǐng)求過(guò)的商品列表我都將他們緩存下來(lái)
_addCache(proList) { cache[this.tab] = { finished: this.listStatus.finished, page: this.page, list: proList, }; },
4.請(qǐng)求數(shù)據(jù)
_getList(type) { let data = {}; data[this.queryName] = this.tab; data.page = this.page; this.$http[this.apiName](data) .then((res) => { this.listStatus.finished = !res.has_more;//更新是否是最后一頁(yè)的狀態(tài) this._handleData(res.items);//處理得到的商品列表 }) .catch((err) => { note(err.message || '出錯(cuò)啦'); }); }, _handleData(proList) { if (this.page === 1) {//表示是tab切換時(shí)請(qǐng)求的數(shù)據(jù),所以直接將items的指向切換 this.items = proList; } else {//因?yàn)槭欠?yè),所以需要把數(shù)據(jù)拼接 this.items = this.items.concat(proList); } this.$store.setData(this.listName, this.items);//把數(shù)據(jù)更新給父組件 this._addCache(this.items);//把數(shù)據(jù)加入緩存 },
5.操作
邏輯部分主要分兩塊:一是列表翻頁(yè),二是tab相關(guān)
列表翻頁(yè)
這部分的邏輯比較簡(jiǎn)單,主要分兩點(diǎn)
_loadmore() { this.page = this.page + 1; this._getList(); },
其實(shí)對(duì)于手機(jī)列表的上拉翻頁(yè)操作,還有很多的點(diǎn)要去注意,比如如何去避免連續(xù)請(qǐng)求等,由于我將這些交給了另一個(gè)專(zhuān)注列表渲染的組件,這里就不需要再去考慮這些操作。
tab相關(guān)
tab切換
tab切換的時(shí)候主要是兩點(diǎn)
changeTab(id) { this.tab = id; this.$store.setData(this.tabName, this.tab);//將tab的指向同步給父組件 this._scrollToTab();//視圖回到頂部 if (cache[this.tab]) { const target = cache[this.tab]; this.listStatus.finished = target.finished; this.page = target.page; this.items = target.list; this.$store.setData(this.listName, this.items);//將商品列表同步給父組件 } else { this.page = 1; this._getList(); } }, //視圖回到頂部 _scrollToTab() { let scrollTop = document.documentElement.scrollTop || document.body.scrollTop; let productsTop = this.$refs.products.$el.offsetTop;//商品列表距離頂部的距離 let topHeight = this.$refs.tabNav.offsetHeight;//tab欄的高度 if (scrollTop > productsTop) { window.scrollTo(0, productsTop - topHeight); } },
吸頂
在吸頂?shù)臅r(shí)候,需要對(duì)tab欄的樣式做一些小小的變動(dòng),所以需要一個(gè)變量來(lái)知道是否吸頂了
handleNavFixed() { this.stickyTop = this.$store.getData('stickyTop') || 0;//吸頂?shù)母叨? window.onscroll = (e) => { let top = document.documentElement.scrollTop || document.body.scrollTop; let tabHeight = this.$refs.tabNav.offsetTop - top - 1; if (tabHeight <= this.stickyTop && !this.isTabFixed) {//結(jié)合判斷為了避免重復(fù)計(jì)算 this.isTabFixed = true; } if (tabHeight >= this.stickyTop && this.isTabFixed) { this.isTabFixed = false; } }; },
6.組件相關(guān)
作為一個(gè)組件,不同點(diǎn)在于需要做到的是可用性和通用性。 對(duì)于組件如何更好的得到父組件的值并把更新的值傳回父組件方面,是我在開(kāi)發(fā)過(guò)程中的一個(gè)卡點(diǎn),最后我用了一套基于vue的組件通行機(jī)制。這種通行機(jī)制的實(shí)現(xiàn)網(wǎng)上很多,這里就不詳細(xì)說(shuō)了。通行機(jī)制主要有兩個(gè)功能
由于將tab列表都作為插槽傳入,所以初始數(shù)據(jù)并不需要關(guān)心,需要關(guān)心的只是更新數(shù)據(jù)。
對(duì)于不同的頁(yè)面,tab列表的名稱(chēng),tab定位的名稱(chēng),商品列表的名稱(chēng),接口的名稱(chēng),請(qǐng)求接口的參數(shù)都可以會(huì)不一樣,所以我在這里將這些項(xiàng)作為參數(shù),在初始化這個(gè)組件的時(shí)候需要傳入
//組件部分 init(data = {}) { this.listStatus.finished = !data.hasMore; this.tabName = data.tabName; this.listName = data.listName; this.apiName = data.apiName; this.queryName = data.queryName; this.handleNavFixed();//判斷是否吸頂 }, //調(diào)用組件 this.$bus.emit('tab-list.init', { tabName: 'tab', listName: 'items', apiName: 'homeList', queryName: 'tab_id', hasMore: this.hasMore, });
總結(jié)
以上所述是小編給大家介紹的基于vue的tab-list類(lèi)目切換商品列表組件的示例代碼,希望對(duì)大家有所幫助!