商品列表分页和排序功能实现

版权声明: https://blog.csdn.net/xyphf/article/details/84453079

本节我们实现商品列表的升降序、价格的过滤、商品列表的分页和loading功能

实现排序

既然要实现排序,必然要获取一个排序的参数,通过req.param()来获取前端传过来的参数

let sort = req.param("sort");

let = params = {};

let goodsModel = Goods.find(params);

将前端升序或降序的参数传递过来

声明对哪个字段进行排序 ,这里如salePrice金额 sort 1 为升序,-1 为降序

goodsModel.sort({'salePrice':sort});

routes/goods.js

var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Goods = require('../models/goods');

// 连接MongoDB数据库
mongoose.connect('mongodb://保密哈:27017/dumall');

// 通过mongoose.connect.on的形式去监听数据库有没有连接成功
mongoose.connection.on("connected",function () {
    console.log("MongoDB connected success.")
})
// 连接失败
mongoose.connection.on("error",function () {
    console.log("MongoDB connected fail.")
})
// 连接断开
mongoose.connection.on("disconnected",function () {
    console.log("MongoDB connected disconnected.")
})

// next是往后继续执行的对象
router.get("/", function (req,res,next) {
    let page = parseInt(req.param("page")); // 获取分页参数 第几页
    let pageSize = parseInt(req.param("pageSize")); // 获取一页多少条数据 必须要是数字
    let sort = req.param("sort"); // 获取排序参数
    let skip = (page-1)*pageSize; // 分页计算公式
    let = params = {};

    // 通过skip param 和limit来实现分页, skip表示跳过几条数据 limit表示一页多少条数据
    let goodsModel = Goods.find(params).skip(skip).limit(pageSize);
    // 声明对哪个字段进行排序 ,这里如salePrice金额 sort 1 为升序,-1 为降序
    goodsModel.sort({'salePrice':sort});
    // 第一个是参数,目前没有入参
    // 返回的是两个参数,第一个是报错err,第二个是文档
    // 因为这里不是普通的查询,经过到这里已经执行了很多步骤了 下面通过exec来执行我们的方法
    // exec这里不需要传入参数了,因为前面已经find 拿到结果了
    goodsModel.exec(function (err,doc) {
        
        if(err) {
            res.json({
                status:'1',
                msg:err.message
            });
        } else {
            // 如果没有报错就把结果输出
            res.json({
                status:'0',
                msg:'',
                result:{
                    count: doc.length,
                    list: doc
                }
            });
        }
    });
})

// 通过module.exports进行输出,这样才能加载到
module.exports = router;

我们访问测试一下 

升序 http://127.0.0.1:3000/goods?page=1&pageSize=8&sort=1

降序 

查询第二页数据

至此后台接口已经实现了分页和价格排序功能

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

网页实现升序降序逻辑

分页及价格过滤

vue滚动加载 分页插件  https://www.npmjs.com/package/vue-infinite-scroll

安装分页插件 npm install vue-infinite-scroll --save

v-infinite-scroll="loadMore"   表示滚动的时候加载loadMore方法

infinite-scroll-disabled="busy"  是否需要禁用此方法,如果busy是true的话,那么默认滚动就会失效,如果是flase就可以滚动

infinite-scroll-distance="10"  鼠标滚动的距离离下面有多远,来触发我们的加载

安装完在vue的main.js里面使用一下

import infiniteScroll from 'vue-infinite-scroll'

Vue.use(infiniteScroll)

>>>>>

价格过滤功能实现

传一个priceLevel:this.priceChecked, // 筛选选择价格区间参数

node后端代码 routes/goods.js

var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Goods = require('../models/goods');

// 连接MongoDB数据库
mongoose.connect('mongodb://47.100.191.231:27017/dumall');

// 通过mongoose.connect.on的形式去监听数据库有没有连接成功
mongoose.connection.on("connected",function () {
    console.log("MongoDB connected success.")
})
// 连接失败
mongoose.connection.on("error",function () {
    console.log("MongoDB connected fail.")
})
// 连接断开
mongoose.connection.on("disconnected",function () {
    console.log("MongoDB connected disconnected.")
})

// next是往后继续执行的对象
router.get("/", function (req,res,next) {
    let page = parseInt(req.param("page")); // 获取分页参数 第几页
    let pageSize = parseInt(req.param("pageSize")); // 获取一页多少条数据 必须要是数字
    let priceLevel = req.param("priceLevel"); // 接收筛选价格
    let sort = req.param("sort"); // 获取排序参数
    let skip = (page-1)*pageSize; // 分页计算公式
    var priceGt = '',priceLte = ''; // 筛选价格的区间
    let = params = {};
    // 当priceLevel不等于all是执行,默认是all
    if(priceLevel!='all'){
        switch (priceLevel){
            case '0':
                priceGt = 0; priceLte=100; 
                break;
            case '1':
                priceGt = 100; priceLte=500; 
                break;
            case '2':
                priceGt = 500; priceLte=1000; 
                break;
            case '3':
                priceGt = 1000; priceLte=5000; 
                break;
        }
        params = {
            salePrice:{
                $gt:priceGt, // 筛选价格大于priceGt
                $lte:priceLte // 筛选价格小于priceLte
            }
        }
    }

    // 通过skip param 和limit来实现分页, skip表示跳过几条数据 limit表示一页多少条数据
    let goodsModel = Goods.find(params).skip(skip).limit(pageSize);
    // 声明对哪个字段进行排序 ,这里如salePrice金额 sort 1 为升序,-1 为降序
    goodsModel.sort({'salePrice':sort});
    // 第一个是参数,目前没有入参
    // 返回的是两个参数,第一个是报错err,第二个是文档
    // 因为这里不是普通的查询,经过到这里已经执行了很多步骤了 下面通过exec来执行我们的方法
    // exec这里不需要传入参数了,因为前面已经find 拿到结果了
    goodsModel.exec(function (err,doc) {
        
        if(err) {
            res.json({
                status:'1',
                msg:err.message
            });
        } else {
            // 如果没有报错就把结果输出
            res.json({
                status:'0',
                msg:'',
                result:{
                    count: doc.length,
                    list: doc
                }
            });
        }
    });
})

// 通过module.exports进行输出,这样才能加载到
module.exports = router;

vue前端代码

<template>
    <div>
      <nav-header></nav-header>
      <nav-bread>
        <span>Goods</span>
      </nav-bread>
      <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 cur">Default</a>
            <a @click="showFilterPop" href="javascript:void(0)" class="price">
              Price 
              <svg class="icon icon-arrow-short"><use xlink:href="#icon-arrow-short"></use></svg>
            </a>
            <a href="javascript:void(0)" class="filterby stopPop" @click="showFilterPop">Filter by</a>
          </div>
          <div class="accessory-result">
            <!-- filter -->
            <div class="filter stopPop" id="filter">
              <dl class="filter-price">
                <dt>Price:</dt>
                <dd><a href="javascript:void(0)" v-bind:class="{'cur':priceChecked=='all'}" @click="priceChecked='all'">All</a></dd>
                <dd v-for="(price,index) in priceFilter" :key="index">
                  <a href="javascript:void(0)" @click="setPriceFilter(index)" v-bind:class="{'cur':priceChecked==index}">{{ price.startPrice }}-{{ price.endPrice }}</a>
                </dd>
              </dl>
            </div>

            <!-- search result accessories list -->
            <div class="accessory-list-wrap">
              <div class="accessory-list col-4">
                <ul>
                  <li v-for="(item,index) in goodsList" :key="index">
                    <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 class="load-more" v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="30">
                    <img src="./../assets/loading-spinning-bubbles.svg" alt="" v-show="loading">
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <!-- <div class="md-overlay" v-show="overLayFlag" @click="closePop"></div> -->
      <nav-footer></nav-footer>
   </div>
</template>
<script>
    import './../assets/css/base.css'
    import './../assets/css/product.css'
    import './../assets/css/checkout.css'
    import './../assets/css/login.css'
    import NavHeader from '@/components/NavHeader.vue'
    import NavFooter from '@/components/NavFooter.vue'
    import NavBread from '@/components/NavBread.vue'
    import axios from 'axios'
    
    export default {
        data () {
            return {
                goodsList: [],
                sortFlag: true, // 排序字段
                page:1, // 默认页
                pageSize: 8, // 默认一页显示8条数据
                busy:true,
                loading:true,
                priceFilter:[
                  {
                      startPrice:'0.00',
                      endPrice:'100.00'
                  },
                  {
                    startPrice:'100.00',
                    endPrice:'500.00'
                  },
                  {
                    startPrice:'500.00',
                    endPrice:'1000.00'
                  },
                  {
                    startPrice:'1000.00',
                    endPrice:'5000.00'
                  }
                ],
                priceChecked:'all'
            }
        },
        components: {
          NavHeader,
          NavFooter,
          NavBread
        },
        mounted () {
          this.getGoodList();
        },
        methods: {
          getGoodList (flag) {
            var param = { // 分页及排序参数
              page:this.page,
              pageSize: this.pageSize,
              sort: this.sortFlag?1:-1,  // 升序是1 降序是-1
              priceLevel: this.priceChecked
            }
            this.loading = true;
            axios.get("/goods", {params:param}).then((result)=>{
              let res = result.data;
              this.loading = false;
              if(res.status=="0"){
                if(flag){ // 如果是分页需要累计
                     // 将数组进行串联起来 concat表示将数组连接起来
                  this.goodsList = this.goodsList.concat(res.result.list);
                  if(res.result.count == 0){
                    this.busy = true;
                  } else {
                    this.busy = false;
                  }
                } else { // 普通的请求
                  this.goodsList = res.result.list; 
                  this.busy = false;
                }
              } else {
                this.goodsList = [];
              }
            });
          },
          showFilterPop() { // 排序
                // this.filterBy = true;
                // this.overLayFlag = true;
                this.sortFlag = ! this.sortFlag; // 点击后升序降序切换
                this.page = 1; // 点击升降序后默认从第一页显示
                this.getGoodList(); // 重新加载一次
          },
          loadMore () {
              this.busy = true; // 在请求成功之前禁止再滚动加载
              // 鼠标滚动实在太快了,滚动一秒钟可能有上千个请求,这样对服务器压力太大 因此必须要通过setTimeout来控制
              // 只有第一个请求结束以后才能请求第二个
              setTimeout(() => {
                  this.page++; // 滚动之后要给page++
                  this.getGoodList(true);
              }, 500);
          },
          setPriceFilter(index) { // 价格过滤
            this.priceChecked = index;
            this.page = 1; // 价格过滤后分页从第一页重新开始
            this.getGoodList();
          }
        }
    }
</script>

猜你喜欢

转载自blog.csdn.net/xyphf/article/details/84453079