在線商城項目13-商品列表分頁功能實現(xiàn)

簡介

設想一下,如果商品條目數(shù)量很多,假設有100條襟企,如果我們一次性拉下來,是很影響性能的狮含。所以我們需要為商品列表添加分頁功能顽悼。本篇主要實現(xiàn)以下目的:

  1. 后端分頁功能邏輯實現(xiàn)
  2. 前端分頁功能邏輯實現(xiàn)

1. 后端分頁功能邏輯實現(xiàn)

這里我們有如下約定;

  1. 后端需要接收參數(shù)page和pageSize。
  2. page表示請求第幾頁數(shù)據(jù)几迄。
  3. pageSize表示每頁返回的數(shù)目蔚龙。
  4. 按pageSize分頁并返回指定頁數(shù)的數(shù)據(jù)。

修改routes/goods.js文件如下:

/* GET goods */
router.get('/', function (req, res, next) {
    // 只有接口請求帶參數(shù)sort=priceDown才會按價格降序
    let sort = req.query['sort'] === 'priceDown'?-1:1;
    let startPrice = req.query['startPrice'];
    let endPrice = req.query['endPrice'];
    let page = parseInt(req.query['page']);
    let pageSize = parseInt(req.query['pageSize']);

    // 價格篩選處理邏輯
    startPrice = startPrice? parseInt(startPrice):0;
    endPrice = endPrice?parseInt(endPrice):undefined;
    console.log(startPrice, endPrice);
    let params = {};
    if (endPrice) {
        params = {salePrice: {$gt: startPrice, $lte: endPrice}};
    } else {
        params = {salePrice: {$gt: startPrice}};
    }

    // 分頁處理邏輯
    if (!(page > 0 && pageSize > 0)) {
        res.json({
            code: '801',
            msg: '請求參數(shù)有誤'
        });
        return;
    }
    let skip = (page - 1)*pageSize;

    // 查詢起始價(不包含)到結(jié)尾價(包含)區(qū)間的商品,并分頁返回
    let query = Good.find(params).skip(skip).limit(pageSize);
    query.sort({salePrice: sort});
    query.exec((err, doc) => {
        if (err) {
            res.json({
                code: '900',
                msg: err.message || '服務器錯誤'
            })
        } else {
            res.json({
                code: '000',
                msg: '',
                result: {
                    count: doc.length,
                    list: doc
                }
            })
        }
    });
});

2. 前端分頁功能邏輯實現(xiàn)

這里我們不再詳述與后端分離開發(fā)的邏輯映胁,直接使用已經(jīng)開發(fā)好的后端接口來看效果木羹。
step1 在前端寫死分頁參數(shù)請求數(shù)據(jù)并展示
此處由于后端返回的數(shù)據(jù)結(jié)構(gòu)有了變化,為了看到效果,我們首先要更改一下前端數(shù)據(jù)處理邏輯坑填。

export default {
  data () {
    return {
      prdList: [], // 產(chǎn)品列表
      // 價格過濾列表
      priceFilterList: [
        {
          startPrice: 0,
          endPrice: 100
        },
        {
          startPrice: 100,
          endPrice: 500
        },
        {
          startPrice: 500,
          endPrice: 2000
        },
        {
          startPrice: 2000
        }
      ],
      priceChecked: 'all', // 選中的價格過濾列表項
      filterPrice: null, // 選中的價格過濾列表對象
      isShowFilterBy: false, // 是否展示過濾列表彈窗
      isShowOverLay: false, // 是否展示遮罩層
      page: 1,
      pageSize: 8,
      sortChecked: 'default',
      isPriceUp: true
    }
  },
  computed: {
    isPriceArrowUp () {
      return !this.isPriceUp
    }
  },
  components: {
    PageHeader,
    PageBread,
    PageFooter
  },
  created () {
    this.getPrdList()
  },
  methods: {
    // 請求接口獲取產(chǎn)品列表數(shù)據(jù)
    getPrdList () {
      queryPrdObj = Object.assign({}, this.filterPrice, {page: this.page, pageSize: this.pageSize, sort: this.sortChecked})
      axios.get('/api/goods', {params: queryPrdObj}).then((res) => {
        console.log('res', res)
        let data = (res && res.data) || {}
        if (data.code === '000') {
          let result = data.result || {}
          this.prdList = result.list || []
          console.log('prdList', this.prdList)
        } else {
          alert(`err:${data.msg || '系統(tǒng)錯誤'}`)
        }
      })
    },
    // 選取價格過濾列表項
    checkPriceFilter (index) {
      this.priceChecked = index
      this.filterPrice = index === 'all' ? null : this.priceFilterList[index]
      this.getPrdList()
      this.closeFilterBy()
    },
    // 展示過濾列表彈窗
    showFilterBy () {
      this.isShowFilterBy = true
      this.isShowOverLay = true
    },
    // 關閉過濾列表彈窗
    closeFilterBy () {
      this.isShowFilterBy = false
      this.isShowOverLay = false
    },
    checkSort (val) {
      this.sortChecked = val
      if (val === 'priceUp' || val === 'priceDown') {
        this.isPriceUp = !this.isPriceUp
      } else {
        this.isPriceUp = true
      }
      this.getPrdList()
    }
  }
}

step2 使用vue-infinite-loading進行上拉加載
關于vue-infinite-loading使用方法見官網(wǎng)抛人。
安裝;

npm install vue-infinite-loading --save
six-tao-1301.gif

修改GoodsList.vue文件如下:

<template>
  <div>
    <PageHeader></PageHeader>
    <PageBread>
      <span>Goods</span>
    </PageBread>
    <div class="accessory-result-page accessory-page">
      <div class="container">
        <div class="filter-nav">
          <span class="sortby">Sort by:</span>
          <a href="javascript:void(0)" class="default" :class="{'cur': sortChecked === 'default'}" @click="checkSort('default')">Default</a>
          <a href="javascript:void(0)" class="price" :class="{'cur': sortChecked === 'priceUp' ||  sortChecked === 'priceDown'}" @click="checkSort(isPriceUp?'priceDown':'priceUp')">Price
            <span v-if="isPriceArrowUp">↑</span>
            <span v-else>↓</span>
            <!--<svg class="icon icon-arrow-short">-->
              <!--<symbol id="icon-arrow-short" viewBox="0 0 25 32">-->
                <!--<title>arrow-short</title>-->
                <!--<path class="path1" d="M24.487 18.922l-1.948-1.948-8.904 8.904v-25.878h-2.783v25.878l-8.904-8.904-1.948 1.948 12.243 12.243z"></path>-->
              <!--</symbol>-->
              <!--<use xlink:href="#icon-arrow-short"></use>-->
            <!--</svg>-->
          </a>
          <a href="javascript:void(0)" class="filterby stopPop" @click="showFilterBy">Filter by</a>
        </div>
        <div class="accessory-result">
          <!-- filter -->
          <div class="filter stopPop" id="filter" :class="{'filterby-show': isShowFilterBy}">
            <dl class="filter-price">
              <dt>Price:</dt>
              <dd><a href="javascript:void(0)" :class="{'cur': priceChecked === 'all'}" @click="checkPriceFilter('all')">All</a></dd>
              <dd v-for="(item, index) in priceFilterList" :key="index">
                <a v-if="item.endPrice" href="javascript:void(0)" :class="{'cur': priceChecked === index}" @click="checkPriceFilter(index)">{{item.startPrice}} - {{item.endPrice}}</a>
                <a v-else href="javascript:void(0)" :class="{'cur': priceChecked === index}" @click="checkPriceFilter(index)">> {{item.startPrice}}</a>
              </dd>
            </dl>
          </div>

          <!-- search result accessories list -->
          <div class="accessory-list-wrap">
            <div class="accessory-list col-4">
              <ul>
                <li v-for="item in prdList" :key="item.productId">
                  <div class="pic">
                    <a href="#"><img v-lazy="`../../../static/${item.productImage}`" alt=""></a>
                  </div>
                  <div class="main">
                    <div class="name">{{item.productName}}</div>
                    <div class="price">{{item.salePrice}}</div>
                    <div class="btn-area">
                      <a href="javascript:;" class="btn btn--m">加入購物車</a>
                    </div>
                  </div>
                </li>
              </ul>
            </div>
            <infinite-loading @infinite="infiniteHandler">
              <span slot="no-more">
                No more ...
              </span>
            </infinite-loading>
          </div>
        </div>
      </div>
    </div>
    <div class="md-overlay" v-show="isShowOverLay" @click="closeFilterBy"></div>
    <PageFooter></PageFooter>
  </div>
</template>

<script>
import PageHeader from '../../components/PageHeader'
import PageBread from '../../components/PageBread'
import PageFooter from '../../components/PageFooter'
import axios from 'axios'
import InfiniteLoading from 'vue-infinite-loading'

let queryPrdObj = {}

export default {
  data () {
    return {
      prdList: [], // 產(chǎn)品列表
      // 價格過濾列表
      priceFilterList: [
        {
          startPrice: 0,
          endPrice: 100
        },
        {
          startPrice: 100,
          endPrice: 500
        },
        {
          startPrice: 500,
          endPrice: 2000
        },
        {
          startPrice: 2000
        }
      ],
      priceChecked: 'all', // 選中的價格過濾列表項
      filterPrice: null, // 選中的價格過濾列表對象
      isShowFilterBy: false, // 是否展示過濾列表彈窗
      isShowOverLay: false, // 是否展示遮罩層
      page: 1,
      pageSize: 8,
      sortChecked: 'default',
      isPriceUp: true
    }
  },
  computed: {
    isPriceArrowUp () {
      return !this.isPriceUp
    }
  },
  components: {
    PageHeader,
    PageBread,
    PageFooter,
    InfiniteLoading
  },
  created () {
    // this.getPrdList()
  },
  methods: {
    // 請求接口獲取產(chǎn)品列表數(shù)據(jù)
    getPrdList ($state) {
      queryPrdObj = Object.assign({}, this.filterPrice, {page: this.page, pageSize: this.pageSize, sort: this.sortChecked})
      axios.get('/api/goods', {params: queryPrdObj}).then((res) => {
        console.log('res', res)
        this.page++
        let data = (res && res.data) || {}
        if (data.code === '000') {
          let result = data.result || {}
          this.prdList = this.prdList.concat(result.list || [])
          if (result.count === this.pageSize) {
            $state.loaded()
          } else {
            $state.complete()
          }
        } else {
          alert(`err:${data.msg || '系統(tǒng)錯誤'}`)
          $state.complete()
        }
      })
    },
    // 選取價格過濾列表項
    checkPriceFilter (index) {
      this.priceChecked = index
      this.filterPrice = index === 'all' ? null : this.priceFilterList[index]
      this.getPrdList()
      this.closeFilterBy()
    },
    // 展示過濾列表彈窗
    showFilterBy () {
      this.isShowFilterBy = true
      this.isShowOverLay = true
    },
    // 關閉過濾列表彈窗
    closeFilterBy () {
      this.isShowFilterBy = false
      this.isShowOverLay = false
    },
    checkSort (val) {
      this.sortChecked = val
      if (val === 'priceUp' || val === 'priceDown') {
        this.isPriceUp = !this.isPriceUp
      } else {
        this.isPriceUp = true
      }
      this.getPrdList()
    },
    infiniteHandler ($state) {
      this.getPrdList($state)
    }
  }
}
</script>

總結(jié)

到此,商品列表頁的查詢展示邏輯基本上完成了脐瑰。
我們提交代碼:

  1. six-tao
git status
git diff
git commit -am 'add vue-infinite-loading'
git push
  1. six-tao-server
git status
git diff
git commit -am 'paging logic done'
git push
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妖枚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子苍在,更是在濱河造成了極大的恐慌绝页,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忌穿,死亡現(xiàn)場離奇詭異抒寂,居然都是意外死亡,警方通過查閱死者的電腦和手機掠剑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門屈芜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人朴译,你說我怎么就攤上這事井佑。” “怎么了眠寿?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵躬翁,是天一觀的道長。 經(jīng)常有香客問我盯拱,道長盒发,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任狡逢,我火速辦了婚禮宁舰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奢浑。我一直安慰自己蛮艰,他們只是感情好,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布雀彼。 她就那樣靜靜地躺著壤蚜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪徊哑。 梳的紋絲不亂的頭發(fā)上袜刷,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音莺丑,去河邊找鬼著蟹。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的草则。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蟹漓,長吁一口氣:“原來是場噩夢啊……” “哼炕横!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起葡粒,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤份殿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嗽交,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卿嘲,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年夫壁,在試婚紗的時候發(fā)現(xiàn)自己被綠了拾枣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡盒让,死狀恐怖梅肤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情邑茄,我是刑警寧澤姨蝴,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站肺缕,受9級特大地震影響左医,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜同木,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一浮梢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泉手,春花似錦黔寇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颊郎,卻和暖如春憋飞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姆吭。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工榛做, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓检眯,卻偏偏與公主長得像厘擂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锰瘸,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容