本节我们实现商品列表的升降序、价格的过滤、商品列表的分页和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​

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

降序 

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

查询第二页数据

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

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

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

网页实现升序降序逻辑

分页及价格过滤

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)

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

>>>>>

价格过滤功能实现

传一个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>