zoukankan      html  css  js  c++  java
  • 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>

    分页最终效果图:

     

     

  • 相关阅读:
    HTTP状态码
    MySQL的order by时区分大小写
    CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentHashMap的实现原理和适用场景
    Map接口
    Python中创建守护进程
    df说磁盘空间满了, du说没有,到底谁是对的
    几种分布式文件系统对比
    Unity:控制粒子特效的移动方向
    创建NuGet包
    NuGet的简单使用
  • 原文地址:https://www.cnblogs.com/luckyplj/p/11608421.html
Copyright © 2011-2022 走看看