用bootstrap给flask商品中心造个商品列表页

1,697次阅读
没有评论

共计 9479 个字符,预计需要花费 24 分钟才能阅读完成。

用bootstrap给flask商品中心造个商品列表页

前面已经完成一个简单的商品中心服务提供商品列表接口,也用selenium捞了点数据,现在得折腾个展示页面,这个前端展示就直接html5+bootstrap+jquery来搞了,没有其他后端服务~

CV个导航栏

上bootstrap示例中cv一个nav下来改改

    <nav class="navbar navbar-expand-lg navbar-light bg-light rounded">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExample09" aria-controls="navbarsExample09" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarsExample09">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item active">
          <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled">Disabled</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-expanded="false">Dropdown</a>
          <div class="dropdown-menu">
            <a class="dropdown-item" href="#">Action</a>
            <a class="dropdown-item" href="#">Another action</a>
            <a class="dropdown-item" href="#">Something else here</a>
          </div>
        </li>
      </ul>
      <form class="form-inline my-2 my-md-0">
        <input class="form-control" type="text" placeholder="Search" aria-label="Search">
      </form>
    </div>
  </nav>

增加个logo

随便用一个吧,就用grafana得图标整整

        <a class="navbar-brand" href="#">
            <img src="https://grafana.com/static/img/menu/grafana2.svg" width="" height="" alt=""
                 class="logo-img">
        </a>

增加点效果,让logo图标选转起来,可以使用keyframes 来配置动画效果

    <style>
        .rounded-circle {
            width: 30px;
            height: 30px;
        }

        .rotate {
            animation: rotation 3s infinite linear;
        }

        @keyframes rotation {
            from {
                transform: rotate(0deg);
            }
            to {
                transform: rotate(359deg);
            }
        }
    </style>

最后nav中得图标img标签用上这个class即可

         <a class="navbar-brand" href="#">
            <img src="https://grafana.com/static/img/menu/grafana2.svg" width="" height="" alt=""
                 class="logo-img rounded-circle rotate">
        </a>

固定导航栏

如果要让导航栏固定在头部,可以给导航加个stick-top类属性

<nav class="navbar sticky-top navbar-expand-lg  navbar-light bg-light">
</nav>

搜索框调整

虽然搜索服务还没整,但是也先调整下样式,后面服务上了再细细搞

            <form class="form-inline my-2 my-lg-0">
                <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
                <button class="btn btn-outline-dark my-2 my-sm-0" type="submit">Search</button>
            </form>

填充商品列表

创建个id为product-list的div,后面jq就根据这个id来定位更新元素

    <div class="row" id="product-list">
    </div>

用ajax获取后端数据,然后拼接html元素

    var products_center_addr = "http://products-center.xadocker.cn"
    function renderProductList(page) {
        $.getJSON(products_center_addr + '/products?per_page=24&page=' + page, function (data) {
            var products = data.products;
            totalPages = data.total_pages;

            var html = '';
            for (var i = 0; i < products.length; i++) {
                var product = products[i];
                html += '<div class="card col-2" >';
                html += '<img class="card-img-top" src="' + product.img + '" alt="' + product.title + '" title="' + product.title + '">';
                html += '<div class="card-body p-0">';
                html += '<div class="row align-items-end">'
                html += '<div class="col text-left">\n' +
                    '      <span style="font-size: 15px; color: red;">¥' + product.price + '</span></div>';
                html += '<h6 class="card-title" title="' + product.title + '">' + product.title + '</h6>';
                html += '<div class="card-text" title="' + product.description + '"><span style="font-size: 15px; color: gray;">' + product.description + '</span></div>';


//					html += '<div class="col text-right">\n' +
//                        '      <span style="font-size: 10px; color: gray;">库存:' + 10 + '</span></div>';
                html += '</div>'
                html += '</div></div>';
            }
            $('#product-list').html(html);
        });
    }

整个分页组件

在product-list的div下创个nav用来放置分页组件

    <nav>
        <ul class="pagination" id="pagination">
        </ul>
    </nav>

jq中处理分页信息方法

    var currentPage = 1;
    var totalPages = 1;
    var viewPagesNum = 5;
    function renderPagination() {
        // 显示当前页码前后两个页码
        var startPage = Math.max(1, currentPage - Math.floor(viewPagesNum / 2));
        var endPage = Math.min(totalPages, currentPage + Math.floor(viewPagesNum / 2));
        if (startPage == 1) {
            endPage = viewPagesNum
        }
        if (endPage == totalPages) {
            startPage = totalPages - viewPagesNum + 1
        }


        var html = '';

        // 添加“上一页”按钮
        html += '<li class="page-item' + (currentPage == 1 ? ' disabled' : '') + '"><a class="page-link" href="#" onclick="gotoPage(' + (currentPage - 1) + ')">上一页</a></li>';

        // 添加页码按钮
        for (var i = startPage; i <= endPage; i++) {
            html += '<li class="page-item' + (i == currentPage ? ' active' : '') + '"><a class="page-link" href="#" onclick="gotoPage(' + i + ')">' + i + '</a></li>';
        }

        // 添加“下一页”按钮
        html += '<li class="page-item' + (currentPage == totalPages ? ' disabled' : '') + '"><a class="page-link" href="#" onclick="gotoPage(' + (currentPage + 1) + ')">下一页</a></li>';
        $('#pagination').html(html);
    }

效果

效果图

最后效果如下,修修整整,浪费时间,没想到CV工程师不是CV这么简单。。。就先这样吧,反正博主只要能展示后端数据就好了

用bootstrap给flask商品中心造个商品列表页

最后的代码

<!DOCTYPE html>
<html>
<head>
    <title>DuckDuckRunning</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <script src="js/jquery.min.js"></script>
    <script src="js/popper.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <style>
        body {
            background-color: #f5f5f5;
        }

        .row {
            margin: 0px;
        }

        .card {
            margin: 0px;
            border: none;
            margin-top: 10px;
            margin-bottom: 10px;
            padding-top: 10px;
            padding-left: 5px;
            padding-right: 5px;
            padding-bottom: 10px;
        }

        .card:hover {
            z-index: 1;
            border: 1px solid #c9c9c9; /* 设置边框为浅灰色 */
            box-shadow: 0 0 1px 1px #f8f8f8;
        }

        .price-text {
            font-size: 15px;
            color: red;
            margin-bottom: 0;

        }

        .stock-text {
            margin-left: 5px;
            margin-bottom: 0;
            font-size: 10px;
            color: grey;
        }

        .card-title, .card-text {
            margin: 0;
            padding-left: 10px;
            margin-top: 5px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            max-width: 100%;
        }

        .navbar-brand {
            height: 100%;
            display: flex;
            align-items: center;
        }

        .rounded-circle {
            width: 30px;
            height: 30px;
        }

        .rotate {
            animation: rotation 3s infinite linear;
        }

        @keyframes rotation {
            from {
                transform: rotate(0deg);
            }
            to {
                transform: rotate(359deg);
            }
        }

        .red-line {
            height: 2px;
            background-color: red;
        }

        .navbar {
            border-bottom: 2px solid red;
        }

        .navbar-nav .nav-item.active .nav-link {
            /*background-color: red;*/
            color: red;

        }

        .navbar-nav li a {
            font-weight: bold;
        }
    </style>
</head>
<body>


<div class="container">

    <nav class="navbar sticky-top navbar-expand-lg  navbar-light bg-light">
        <a class="navbar-brand" href="#">
            <img src="https://grafana.com/static/img/menu/grafana2.svg" width="" height="" alt=""
                 class="logo-img rounded-circle rotate">
        </a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                    <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">秒杀</a>
                </li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown"
                       aria-expanded="false">
                        类别
                    </a>
                    <div class="dropdown-menu">
                        <a class="dropdown-item" href="#">电脑</a>
                        <a class="dropdown-item" href="#">手机</a>
                        <div class="dropdown-divider"></div>
                        <a class="dropdown-item" href="#">相机</a>
                    </div>
                </li>
            </ul>
            <form class="form-inline my-2 my-lg-0">
                <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
                <button class="btn btn-outline-dark my-2 my-sm-0" type="submit">Search</button>
            </form>
        </div>
        <div class="red-line"></div>
    </nav>

    <div class="row" id="product-list">
    </div>
    <nav>
        <ul class="pagination" id="pagination">
        </ul>
    </nav>
</div>
<script>
    var currentPage = 1;
    var totalPages = 1;
    var viewPagesNum = 5;
    var products_center_addr = "http://products-center.xadocker.cn"

    function renderProductList(page) {
        $.getJSON(products_center_addr + '/products?per_page=24&page=' + page, function (data) {
            var products = data.products;
            totalPages = data.total_pages;

            var html = '';
            for (var i = 0; i < products.length; i++) {
                var product = products[i];
                html += '<div class="card col-2" >';
                html += '<img class="card-img-top" src="' + product.img + '" alt="' + product.title + '" title="' + product.title + '">';
                html += '<div class="card-body p-0">';
                html += '<div class="row align-items-end">'
                html += '<div class="col text-left">\n' +
                    '      <span style="font-size: 15px; color: red;">¥' + product.price + '</span></div>';
                html += '<h6 class="card-title" title="' + product.title + '">' + product.title + '</h6>';
                html += '<div class="card-text" title="' + product.description + '"><span style="font-size: 15px; color: gray;">' + product.description + '</span></div>';


//					html += '<div class="col text-right">\n' +
//                        '      <span style="font-size: 10px; color: gray;">库存:' + 10 + '</span></div>';
                html += '</div>'
                html += '</div></div>';
            }
            $('#product-list').html(html);
            renderPagination();
        });
    }

    function renderPagination() {
        // 显示当前页码前后两个页码
        var startPage = Math.max(1, currentPage - Math.floor(viewPagesNum / 2));
        var endPage = Math.min(totalPages, currentPage + Math.floor(viewPagesNum / 2));
        if (startPage == 1) {
            endPage = viewPagesNum
        }
        if (endPage == totalPages) {
            startPage = totalPages - viewPagesNum + 1
        }


        var html = '';

        // 添加“上一页”按钮
        html += '<li class="page-item' + (currentPage == 1 ? ' disabled' : '') + '"><a class="page-link" href="#" onclick="gotoPage(' + (currentPage - 1) + ')">上一页</a></li>';

        // 添加页码按钮
        for (var i = startPage; i <= endPage; i++) {
            html += '<li class="page-item' + (i == currentPage ? ' active' : '') + '"><a class="page-link" href="#" onclick="gotoPage(' + i + ')">' + i + '</a></li>';
        }

        // 添加“下一页”按钮
        html += '<li class="page-item' + (currentPage == totalPages ? ' disabled' : '') + '"><a class="page-link" href="#" onclick="gotoPage(' + (currentPage + 1) + ')">下一页</a></li>';
        $('#pagination').html(html);
    }

    function gotoPage(page) {
        if (page < 1 || page > totalPages) {
            return;
        }
        currentPage = page;
        renderProductList(page);
    }

    $(document).ready(function () {
        renderProductList(1);
    });
</script>
</body>
</html>

部署文件

dockerfile

FROM openresty/openresty:1.21.4.1-buster

WORKDIR /app

COPY . .

COPY nginx.conf /etc/nginx/conf.d/default.conf

RUN rm -f nginx.conf Dockerfile
# 暴露端口
EXPOSE 80

nginx.conf

server {
  listen 80;
  server_name mall.xadocker.cn;  # 修改为你的域名

  # 设置网站根目录
  root /app;

  # 设置默认页面
  index index.html;

  # 静态资源缓存设置
  location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    expires 1y;
    add_header Cache-Control "public, max-age=31536000";
    access_log off;
  }

  # 处理HTML页面请求
  location / {
    try_files $uri $uri/ /index.html;
  }

  # 处理404错误
  error_page 404 /404.html;
  location = /404.html {
    internal;
  }
}

正文完
 
xadocker
版权声明:本站原创文章,由 xadocker 2023-03-07发表,共计9479字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)