035 搭建搜索微服务03----页面分页效果

刚才的查询中,我们默认了查询的页码和每页大小,因此所有的分页功能都无法使用,接下来我们一起看看分页功能条该如何制作。

这里要分两步,

  • 第一步:如何生成分页条

  • 第二步:点击分页按钮,我们做什么

1.如何生成分页条

先看下页面关于分页部分的代码:

 

可以看到所有的分页栏内容都是写死的。

(1)需要的数据

分页数据应该是根据总页数当前页总条数等信息来计算得出。

  • 当前页:肯定是由页面来决定的,点击按钮会切换到对应的页

  • 总页数:需要后台传递给我们

  • 总条数:需要后台传递给我们

我们首先在data中记录下这几个值:page-当前页,total-总条数,totalPage-总页数

var vm = new Vue({
el: "#searchApp",
data: {
ly,
search:{
key:"", // 搜索页面的关键字
page: 1,
},
goodsList:[],
total: 0, // 总条数
totalPage: 0 ,// 总页数
},

因为page是搜索条件之一,所以记录在search对象中。page值我们要将其传到后台进行查询的。

要注意:我们在created钩子函数中,会读取url路径的参数,然后赋值给search。如果是第一次请求页面,page是不存在的。因此为了避免page被覆盖,我们应该这么做:

created(){
            // 判断是否有请求参数
            if(!location.search){
                return;
            }
            // 调用common.js文件中定义的方法,将请求参数字符串格式化为js对象
            const search = ly.parse(location.search.substring(1));
            //对page进行初始化,防止第一次访问时,page为空
            search.page=search.page ? parseInt(search.page) : 1;
            // 记录在data的search对象中
            this.search = search;

            // 发起请求,根据条件搜索
            this.loadData();
        },

不过,这个时候我们自己的search对象中的值就可有可无了

(2)后台提供数据

后台返回的结果中,要包含total和totalPage,我们改造下刚才的接口:

在我们返回的PageResult对象中,其实是有totalPage字段的:

(3)页面计算分页条

首先,把后台提供的数据保存在data中:

loadData(){
                // ly.http.post("/search/page", ly.stringify(this.search)).then(resp=>{
                //注意:http在common.js文件定义的,实际上就是axios
                //resp表示后台响应的数据对象,resp.data为数据
                ly.http.post("/search/page", this.search).then(resp=>{
                    if(resp.data.items.length===0){
                        return
                    }
                    this.total=resp.data.total;
                    this.totalPage=resp.data.totalPage;

                    //遍历goodsList集合
                    resp.data.items.forEach(goods=>{
                        //将skus字段这个json字符串转换为json对象
                        goods.skus=JSON.parse(goods.skus);
                        //扩展一个selected属性
                        goods.selected=goods.skus[0];
                    });
                    this.goodsList=resp.data.items;
                });

然后看下我们要实现的效果:

这里最复杂的是中间的1~5的分页按钮,它需要动态变化。

思路分析

  • 最多有5个按钮,因此我们可以用v-for循环从1到5即可

  • 但是分页条不一定是从1开始:

    • 如果当前页值小于等于3的时候,分页条位置从1开始到5结束

    • 如果总页数小于等于5的时候,分页条位置从1开始到总页数结束

    • 如果当前页码大于3,应该从page-3开始

    • 但是如果当前页码大于totalPage-3,应该从totalPage-5开始

举例分析:若总页数为50

所以,我们的页面这样来做:

 

<!--分页部分-->
            <div class="fr">
                <div class="sui-pagination pagination-large">
                    <ul>
                        <li class="prev disabled">
                            <a href="#">«上一页</a>
                        </li>
                        <!--通过v-for 遍历生成指定个数的li标签,当totalpage<5时,li个标签数为totalpage-->
                        <!--active 通过判断当前页是否等于index(i),设置li标签是否为激活状态-->
                        <li :class="{active : search.page==index(i)}" v-for="i in Math.min(5,totalPage)">
                            <a href="#">{{index(i)}}</a>
                        </li>

                        <li class="dotted"><span>...</span></li>
                        <li class="next">
                            <a href="#">下一页»</a>
                        </li>
                    </ul>
                    <div><span>共10页&nbsp;</span><span>
      到第
      <input type="text" class="page-num"><button class="page-confirm" onclick="alert(1)">确定</button></span></div>
                </div>
            </div>

效果图:

2.点击分页做什么

点击分页按钮后,自然是要修改page的值

所以,我们在上一页下一页按钮添加点击事件,对page进行修改,在数字按钮上绑定点击事件,点击直接修改page:

<!--分页部分-->
            <div class="fr">
                <div class="sui-pagination pagination-large">
                    <ul>
                        <!--若当前页是1,则li标签为失效模式-->
                        <li class="prev " :class="{disabled: search.page==1}" @click="prev()">
                            <a href="#">«上一页</a>
                        </li>
                        <!--通过v-for 遍历生成指定个数的li标签,当totalpage<5时,li个标签数为totalpage-->
                        <!--active 通过判断当前页是否等于index(i),设置li标签是否为激活状态-->
                        <!--@click="search.page=index(i) 绑定点击事件,将当前页设置为index(i)的索引值-->
                        <li :class="{active : search.page==index(i)}" v-for="i in Math.min(5,totalPage)" @click="search.page=index(i)">
                            <a href="#">{{index(i)}}</a>
                        </li>

                        <li class="dotted"><span>...</span></li>
                        <li class="next" :class="{disabled: search.page==totalPage}" @click="next()">
                            <a href="#">下一页»</a>
                        </li>
                    </ul>
                    <div><span>共10页&nbsp;</span><span>
      到第
      <input type="text" class="page-num"><button class="page-confirm" onclick="alert(1)">确定</button></span></div>
                </div>
            </div>

翻页事件的方法(vue对象中的方法):

       prev(){
                //上一页:当前页>1
                if(this.search.page>1){
                    this.search.page--;
                }
            },
            next(){
                //下一页:当前页比总页数少
                if(this.search.page<this.totalPage){
                    this.search.page++;
                }
            },

效果图(重点看分页条):

page发生变化,我们应该去后台重新查询数据。

不过,如果我们直接发起ajax请求,那么浏览器的地址栏中是不会有变化的,没有记录下分页信息。如果用户刷新页面,那么就会回到第一页。

这样不太友好,我们应该把搜索条件记录在地址栏的查询参数中

因此,我们监听search的变化,然后把search的过滤字段拼接在url路径后:

watch:{
    search:{
        deep:true,
        handler(val){
            // 把search对象变成请求参数,拼接在url路径
            window.location.href = "http://www.leyou.com/search.html?" + ly.stringify(val);
        }
    }
},

刷新页面测试,然后就出现重大bug:页面无限刷新!为什么?

因为Vue实例初始化的钩子函数中,我们读取请求参数,赋值给search的时候,也触发了watch监视!也就是说,每次页面创建完成,都会触发watch,然后就会去修改window.location路径,然后页面被刷新,再次触发created钩子,又触发watch,周而复始,无限循环。

所以,我们需要在watch中进行监控,如果发现是第一次初始化,则不继续向下执行。

那么问题是,如何判断是不是第一次?

第一次初始化时,search中的key值肯定是空的,所以,我们这么做:

watch:{
    search:{
        deep:true,
        handler(val,old){
            if(!old || !old.key){
                // 如果旧的search值为空,或者search中的key为空,证明是第一次
                return;
            }
            // 把search对象变成请求参数,拼接在url路径
            window.location.href = "http://www.leyou.com/search.html?" + ly.stringify(val);
        }
    }
}

3.页面顶部分页条

在页面商品列表的顶部,也有一个分页条:

            <div class="top-pagination">
                        <span><i style="color: #222;">{{total}}+</i> 商品</span>
                        <span><i style="color: red;">{{search.page}}</i>/{{totalPage}}</span>
                        <a class="btn-arrow" href="#" style="display: inline-block" @click="prev()">&lt;</a>
                        <a class="btn-arrow" href="#" style="display: inline-block" @click="next()">&gt;</a>
                    </div>

分页最终效果图:

 

 

原文地址:https://www.cnblogs.com/luckyplj/p/11608421.html