ssm(mybatis -plus的使用)0906小众网首页index.ftl制作

  • 续0905

  • 使用art-template模板,来给一些重复性的代码写模板

  • https://aui.github.io/art-template/
    • 当你写完了模板之后,你需要去连接后台响应的数据和模板,然后追加到页面去显示
      • 相比较之前拼接的方法去显示,在需要用到非常多相同格式的数据时,会简单很多
  •  然后就是需要用到评分组件--星型组件

    • 星星插件:https://www.jq22.com/jquery-info6430
    • 要用别人的东西,我们首先要引入别人的插件

      • 然后我们就需要去给需要指定星星插件的标签起个名字方便后续指定
      • data-score="",title也不要漏了
      •        //初始化星形图片目录,前面这一部分不要写错了
                $.fn.raty.defaults.path="/xzw/resources/raty/lib/images/";
      • 这个目录我们要到哪里去初始化呢,可以看官方文档
        • 在初始化目录的时候,报了一个这样的错
        • 解决办法:之前报错是因为引入插件的时候写错了,js不是用link

        • 当上面的错误排除之后,页面上还是不会有效果的,你需要去指定那个标签用到了星型插件,在这个案例当中是在success回调函数末尾指定

  • 然后我们现在要实现,点击加载更多,显示更多数据

    • 首先我们想一下实现的思路:当我们点击加载更多的时候,我们需要触发一个事件,发送一个ajax请求,将当前页传到后台,从而返回当前页的数据,那么我们就需要获取到当前页的页码,所以我们需要在页面上写一个辅助分页的代码,并将其隐藏起来,当我们触发事件之后,获取到辅助分页的默认当前页value值,发送ajax将下一页数据显示出来之后,再将辅助分页的value值+1
      • 因为后台响应的数据res(info)中,有一个current属性,所以可以利用它来+1,然后因为怕数据是字符串类型的,所以给他强转一下
      • 那么我们的分页效果就实现了

      • 当我们使用上面的思想实现分页显示的时候,第一次和后续加载代码上ajax是完全重复的,所以可以优化思路就是要判断哪一次是第一次,所以可以写一个方法来判断,然后后续来调用就可以了
      •  //加载下一页
            function loadNext(isFirst){
                if(isFirst == true){
                    //如果是第一页,页码设置为1,不是,就不会执行
                    $('#nextPage').val(1);
                }
                var nextPage = $('#nextPage').val();//如果是第一页,则取出来的是1
                $.ajax({
                    url: 'books',
                    type: 'get',
                    data: {"page":nextPage},
                    //另一种方式,序列化,就能拿到表单里面的数据,但是这样写需要注意传的数据要和User类能对上
                    // data:$('#frm').serialize(),
                    //如果不需要返回数据,就不用写
                    dataType: 'json',
                    success: function (info) {
                        console.log(info);
                        var bookList = info.records;
                        for (var i = 0; i < bookList.length; i++) {
                            var book = bookList[i];
                            //连接模板与后台响应的结果book
                            var html = template("tpl",book);//将结果拼接在模板上之后,追加到div(bookList)中
                            $('#bookList').append(html);
                        }
                        //表示为星型组件
                        // $('.stars').raty();
                        //readOnly:true设为只读,把stars变为星型组件,stars可以理解为一个标记,在这里把标记了这个名称的变为星型组件
                        $('.stars').raty({readOnly:true});
        
                        //如果当前页,小于总页数,则将辅助分页的下一页的文本框的值改为:当前页+1
                        if(info.current < info.pages){
                            $('#nextPage').val(parseInt(info.current)+1)
                        }else {
                            $('#btnMore').hide()
                            $('#divNoMore').show()
                        }
                    }
                })
            }
        
            $(function () {
                //莫问首页刚打开时,为true,设为1
                loadNext(true);
                //然后就是点击加载更多的时候,调用上面的方法,就不需要写重复的代码了,也是优化代码
                //单击btnMore这个按钮,加载更多,实际上是分页显示
                $('#btnMore').click(function () {
                    loadNext(nextPage);
                })
            })

  •  首先默认是按全部显示,然后我们实现点击其他分类,点击的分类高亮显示

  • 实现思路,点击类别触发单击事件,先清除原本的高亮,然后给当前点击的类别添加高亮
  • html静态原型代码
  • <div class="col-8 mt-2">
                <span data-category="-1" style="cursor:pointer" class="highlight font-weight-bold category mr-2">全部</span> |
                <#list categoryList as category>
                    <a style="cursor:pointer" data-category="${category.categoryId}"
                       class="text-black-50 font-weight-bold category">${category.categoryName}</a>
                <#--如果还有下一个,就输入|这个符号-->
                    <#if category_has_next>|</#if>
                </#list>
            </div>

    js效果实现代码:

    //给导航栏的五个分类元素设置高亮:
            $('.category').click(function () {
                //移除当前高亮
                $('.category').removeClass("highlight");
               /* //再设置category的样式为灰色,因为类别当中你写了行内样式,所以其实可以不写
                $('.category').addClass('text-black-50');*/
                //设置当前点击的对应元素为高亮
                $(this).addClass("highlight");
            })

  • 进行到这一步,我们还只是实现了页面上的效果,还没有实现点击分类和排序立马去后台进行查询显示那么我们现在需要先去后台将功能实现 

  • 在bookServiceImpl,我们需要将业务写好,也就是分页查询写好,原先我们需要在业务层调用dao层的方法,通过到层的方法去执行mapper.xml里面的SQL语句,但是我们用了mybatis-plus,dao层接口继承了BaseMapper,那些简单的CRUD,框架已经帮我们写好了,我们只需要准备好需要的参数,去调用框架里面的方法就好了 ,在分页查询当中,我们主要需要用到Ipage,page(用于分页),QueryWrapper(用来组装条件,常用的可以去csdn看别人写的)
  • @Service
    public class BookServiceImpl implements BookService {
        @Autowired
        private BookMapper bookMapper;
        @Override
        public IPage<Book> paging(Long categoryId,String order,Integer page, Integer rows) {
            Page<Book> p = new Page<Book>(page, rows);
            //组装查询和排序条件
            QueryWrapper<Book> queryWrapper = new QueryWrapper<Book>();
            //按类别查,如果categoryId != null/-1,就查所有类别
            if(categoryId != null && categoryId!= -1){
                queryWrapper.eq("category_id",categoryId);//如果条件满足,就往SQL后面追加条件,相当于where xx == #{xx}
            }
            //排序
            if(order != null){
                if(order.equals("quantity")){//按数量
                    queryWrapper.orderByDesc("evaluation_quantity");//相当于orderby xx desc;
                }else if(order.equals("score")){//按评分
                    queryWrapper.orderByDesc("evaluation_score");
                }
            }
            //按组装好的条件查询
            IPage<Book> pageObject = bookMapper.selectPage(p,queryWrapper);
            return pageObject;
        }
    }

 业务层写完之后,可以先去做个测试,看业务是否写好了,如果写好了,我们就可以通过控制层,连接前后端,从前端获取到用户传过来的参数,将数据显示到页面

  •  控制层代码如下:需要前端传递类别,排序方式,以及页码
    • @Controller
      public class BookController {
          @Autowired
          private CategoryService categoryService;
          @Autowired
          private BookService bookService;
      
          /*显示首页*/
          @GetMapping("/")
          public ModelAndView showIndex(){
              ModelAndView modelAndView = new ModelAndView("/index");
              List<Category> categoryList = categoryService.selectAll();
              modelAndView.addObject("categoryList",categoryList);
              return modelAndView;
          }
      
          @RequestMapping("/books")
          @ResponseBody
          public IPage<Book> selectBooks(Long categoryId,String order,Integer page){
              if(page == null){
                  page = 1;
              }
              IPage<Book> pageObject = bookService.paging(categoryId,order,page,2);
              return pageObject;
          }
      
  •  然后,因为我们的前端页面原型已经搭建好了,那么我们就是需要通过获取用户操作后的参数,通过ajax的方式,传递给控制层,来刷新页面
  • 思路:我们默认第一次是按照全部分类,根据热度排序,然后根据用户的操作,来刷新页面,那么当用户点击其他分类以及排序方式的时候,我们在触发事件让页面高亮的同时,需要利用到我们的辅助分页,实时更新其中相应标签的value值,并同时调用分页查询的方法(此时,因为我们分页查询的条件变多了,那么该获取并传递的参数,我们都需要获取并传递好),在分页方法中,我们也需要改进。​​​​​​​
  •  编写时遇到的问题和注意点

    • 辅助分页当中种类categoryId和排序方式order的value值在什么时候改变,改变什么?
    • 调用方法刷新的时候,要防止数据追加,所以要清空div之前加载过的内容
      • ​​​​​​​ 
    • 按钮的显示与隐藏,需要注意
      • ​​​​​​​​​​​​​​
    • 最后的效果:

到此,我们的index页面就完成了 

index.ftl页面所有代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Title</title>
    <!--https://zhuanlan.zhihu.com/p/196777759&ndash;&gt;
    viewport 视口(可视区窗口),通过meta标签设置。
    viewport 决定了我们的页面能不能在移动端正常显示。
    viewport 默认值980,区间(768 ~ 1024)。

    width: 视口的宽度,width的值为一个正整数,或字符串device-width(设备的实际宽度 = 设备的css像素)。
    不建议设置数字(安卓设备有些不支持)
    height: 视口的高度,一般不需要设置

    user-scalable: 是否允许用户进行页面缩放(包括浏览器)值为no或yes,代表不允许与允许。
    如果不设置user-scalable=no; 移动设备的浏览器为了给用户显示更全面的信息,所以会缩放比例(缩放的不是单个元素,而是整个页面)

    initial-scale: 页面初始缩放值, 值为一个数字(可以带小数)。
    设置initial-scale=1.0;时,其实跟设置width=device-width;是一样的效果。
    设置initial-scale=1.0;时,表示不给移动设备的浏览器进行缩放,还原原始的值。
    如果同时设置width=device-width, initial-scale=1.0;时,因为两个的值都是一样的,所以无法比较。

    如果设置width=400, initial-scale=1.0;时,值不一样时,浏览器会取一个最大的值。

    initial-scale有值的情况下,计算的页面公式:
    缩放比 = css像素 / viewport宽度
    viewport宽度 = css像素 / 缩放比
    minimum-scale: 页面最小能够缩放的比例
    值为一个数字(可以带小数)。

    maximum-scale: 页面最大能够缩放的比例
    值为一个数字(可以带小数)。

    未设置viewport的时候:
    1. 屏幕的宽度默认为980,但不同的型号也会不同。
    2. 用window.innerWidth方法获取。


    注意:
    1、有的时候大家会见到同时写了不允许缩放,又写了最小与最大能够缩放的比例,那这样不是冲突了,为什么都已经写了不允许缩放了,还要写那些?

    原因:
    a.会有一些第三方工具能够破坏user-scalable,比方说一些给父母的手机把文字放大的工具,就会有可能。不过一般是没有问题的。
    b.像iphone5下还会有黑边。
    c.所以写全了,可以避免一些bug。

    2、ios10不支持user-scalable=no,后面事件能解决(阻止dosument的touchstart的默认行为)。
    &ndash;&gt;
    -->
    <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0,user-scalable=no">
    <meta charset="UTF-8">
    <script src="resources/jquery.3.3.1.min.js"></script>
    <link rel="stylesheet" href="resources/bootstrap/bootstrap.css">
    <script src="resources/bootstrap/bootstrap.min.js"></script>
    <script src="resources/art-template.js"></script>
    <#--星型组件-->
    <link rel="stylesheet" href="resources/raty/lib/jquery.raty.css">
    <#--<link rel="stylesheet" href="resources/raty/lib/jquery.raty.js">-->
    <script src="resources/raty/lib/jquery.raty.js"></script>
    <style>
        .highlight {
            color: red !important;
        }

        a:active {
            text-decoration: none !important;
        }

        .container {
            padding: 0px;
            margin: 0px;
        }

        .row {
            padding: 0px;
            margin: 0px;
        }

        /* .col- * {
             padding: 0px;
         }*/
    </style>
</head>


<script>
    //初始化图片目录
    $.fn.raty.defaults.path="resources/raty/lib/images/";

    //加载下一页
    function loadNext(isFirst){
        if(isFirst == true){
            //首先将默认的显示清空,不然后续的分类和排序查询会追加
            $('#bookList').html("");
            //如果是第一页,页码设置为1,不是,就不会执行
            $('#nextPage').val(1);
        }
        var nextPage = $('#nextPage').val();//如果是第一页,则取出来的是1
        var categoryId = $('#categoryId').val();//得到辅助分页当中的类别id
        var order = $('#order').val();//得到根据哪个排序的order值
        $.ajax({
            url: 'books',
            type: 'get',
            data: {"page":nextPage,"categoryId":categoryId,"order":order},
            //另一种方式,序列化,就能拿到表单里面的数据,但是这样写需要注意传的数据要和User类能对上
            // data:$('#frm').serialize(),
            //如果不需要返回数据,就不用写
            dataType: 'json',
            success: function (info) {
                console.log(info);
                var bookList = info.records;
                for (var i = 0; i < bookList.length; i++) {
                    var book = bookList[i];
                    //连接模板与后台响应的结果book
                    var html = template("tpl",book);//将结果拼接在模板上之后,追加到div(bookList)中
                    $('#bookList').append(html);
                }
                //表示为星型组件
                // $('.stars').raty();
                //readOnly:true设为只读,把stars变为星型组件,stars可以理解为一个标记,在这里把标记了这个名称的变为星型组件
                $('.stars').raty({readOnly:true});

                //如果当前页,小于总页数,则将辅助分页的下一页的文本框的值改为:当前页+1
                if(info.current < info.pages){
                    $('#nextPage').val(parseInt(info.current)+1)
                    //这里在分类和排序时使用,因为如果某个分类只有一页时,会发生else部分的隐藏,点击其他分类时就再也看不到加载更多了
                    $('#btnMore').show()
                    $('#divNoMore').hide()
                }else {
                    $('#btnMore').hide()
                    $('#divNoMore').show()
                }
            }
        })
    }

    $(function () {
        //默认首页刚打开时,为true,设页码为1
        loadNext(true);
        //然后就是点击加载更多的时候,调用上面的方法,就不需要写重复的代码了,也是优化代码
        //单击btnMore这个按钮,加载更多,实际上是分页显示
        $('#btnMore').click(function () {
            loadNext();
        })

        //给导航栏的五个分类元素设置高亮:
        $('.category').click(function () {
            //移除当前高亮
            $('.category').removeClass("highlight");
            /* //再设置category的样式为灰色,因为类别当中你写了行内样式,所以其实可以不写
             $('.category').addClass('text-black-50');*/
            //设置当前点击的对应元素为高亮
            $(this).addClass("highlight");
            //同时给辅助分页的div部分赋值
            //首先获取点击的类别的值
            var categoryId = $(this).data("category");
            //然后设置辅助分页的表单赋值<input type="hidden" id="categoryId" value="-1">
            $('#categoryId').val(categoryId)

            //点击其他类别之后,马上查询刷新数据
            loadNext(true);//因为每次点击类别的时候,其实都是重新加载数据
        })

        //按热度还是评价高亮
        $('.order').click(function () {
            $('.order').removeClass("highlight");
            $(this).addClass("highlight");
            //同时给辅助分页的div部分赋值
            //首先获取点击的类别的值
            var order = $(this).data("order");
            //然后设置辅助分页的表单赋值<input type="hidden" id="order" value="quantity">
            $('#order').val(order)
            //点击其他排序方式之后,马上查询刷新数据
            loadNext(true);//因为每次点击其他排序的时候,其实都是重新加载数据
        })
    })



</script>

<#--图片对应数据的模板-->
<script type = "text/html" id="tpl">
    <!--行,包含div1,div2,各占4,8格-->
    <a href="detail" style="color: inherit">
        <!-- 一行二列,左图,右内容-->
        <div class="row mt-2">
            <div class="col-4 mb-2 pr-2">
                <img class="img-fluid" src="{{cover}}">
            </div>
            <div class="col-8 mb-2 pl-0">
                <h5 class="text-truncate">{{bookName}}</h5>
                <div class="mb-2 bg-light small p-2 w-100 text-truncate">{{author}}</div>
                <div class="mb-2 w-100">{{subTitle}}</div>
                <p>
                    <#--这个stars只是一个名字,你可以随便取,上面原型的星型,可以通过插件动态实现-->
                    <span class="stars" data-score="{{evaluationScore}}" title="gorgeous"></span>
                    <span class="mt-2 ml-2">{{evaluationScore}}</span>
                    <span class="mt-2 ml-2">{{evaluationQuantity}}人已评</span>
                </p>
            </div>
        </div>
    </a>
    <hr>
</script>

<body>
<div class="container">
    <!-- 导航部分;-->
    <nav class="navbar navbar-light shadow mr-auto">
        <!-- 导航左logo &ndash;&gt;-->
        <ul class="nav">
            <li class="nav-item">
                <img src="resources/images/logo2.png" class="mt-1" style="width: 100px;" alt="">
            </li>
        </ul>
        <!-- 导航右登录图标 &ndash;&gt;-->
        <a href="login.html" class="btn btn-light btn-sm">
            <img src="images/user_icon.png" style="width:2rem;margin-top:-5px;" class="mr-1">登录
        </a>
    </nav>
    <!-- 第一行 -->
    <div class="row mt-2">
        <div class="col-6 mt-2">
            <h4>热评好书推荐</h4>
        </div>
        <div class="col-8 mt-2">
            <#--data-xxx:bootstrap里面自定义数据,data告诉你这是数据,xxx告诉你这个是什么数据-->
            <span data-category="-1" style="cursor:pointer" class="highlight font-weight-bold category mr-2">全部</span> |
            <#list categoryList as category>
                <a style="cursor:pointer" data-category="${category.categoryId}"
                   class="text-black-50 font-weight-bold category">${category.categoryName}</a>
            <#--如果还有下一个,就输入|这个符号-->
                <#if category_has_next>|</#if>
            </#list>
        </div>
        <div class="col-8 mt-2">
            <#--data-xxx:bootstrap里面自定义数据,data告诉你这是数据,xxx告诉你这个是什么数据-->
            <span data-order="quantity" style="cursor:pointer" class="highlight font-weight-bold text-black-50 mr-3 order" id="hot">按热度</span>
            <span data-order="score" style="cursor:pointer" class="font-weight-bold text-black-50 order" id="pj">按评分</span>
        </div>
    </div>
    <!--列表,由多行组成,每行有二个div列,div1占4列,div2占8列,共12格-->
    <div id="bookList">
        <!--
        color: inherit,将强制继承父值
        因:在a链接的情况下,该color属性通常在用户代理样式表中设置为蓝色
        希望链接具有与文本其余部分相同的文本颜色,则可以使用该inherit值来强制继承和其他文本一样的颜色值
        -->
        <!--加载更多,即分页的按钮 -->
    </div>
    <button type="button" id="btnMore" nextPage="1" class="btn btn-outline-primary btn-lg btn-block">
        点击加载更多
    </button>
    <div id="divNoMore" class="text-center text-black-50 mb-5" style="display: none">没有其他数据了</div>
    <!--辅助分页-->
    <div class="d-none">
        <input type="hidden" id="nextPage" value="2">
        <input type="hidden" id="categoryId" value="-1">
        <input type="hidden" id="order" value="quantity">
    </div>
</div>
</body>
</html>
<!--
quantity 数量
.text-black-50  为黑色文本添加 50% 的不透明度
.text-white-50  为白色文本添加 50% 的不透明度
cursor:pointer  鼠标指针样式手
btn-block  显示并且宽100%
d-none 隐藏
shadow 阴影框效果
btn 变为按钮,点一下可以见框范围
 btn-light 按钮有背景色 鼠标移入按钮框,背景可变
 btn-sm    按钮框设为小屏幕,即变小
 .text-truncate {
      overflow: hidden;        溢出内容隐藏
      text-overflow: ellipsis; 单行文本不折行,显示不了就用省略号表示
      white-space: nowrap;     段落中的文本不进行换行
    }
img-fluid                   图片随父元素的宽度一起变化
img-thumbnail              图片随父元素的宽度一起变化
bg-light   背景浅灰色
w-100      width: 100%
small     字大小和粗细设置
-->

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值