• 阿里百秀后台管理项目笔记 ---- Day03


    来吧展示:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    step1:所有文章数据展示

    1. 引入 functions.php 文件执行数据库查询以及判断用户登录状态
    require_once '../functions.php';
    get_userinfo();
    
    1. 查询文章数据
    $posts = mysql_all('select * from posts;');
    
    1. 文章数据渲染
      在表格中将多余的 tr 标记移除,通过 foreach 遍历查询到的 $posts 变量,绑定数据
    <tbody>
            <?php foreach ($posts as $item): ?>
             <tr>
                <td class="text-center"><input type="checkbox"></td>
                <td><?php echo $item['title']; ?></td>
                <td><?php echo $item['user_id']?></td>
                <td><?php echo $item['category_id']?></td>
                <td class="text-center"><?php echo $item['created']?></td>
                <td class="text-center"><?php echo $item['status']?></td>
                <td class="text-center">
                  <a href="javascript:;" class="btn btn-default btn-xs">编辑</a>
                  <a href="javascript:;" class="btn btn-danger btn-xs">删除</a>
                </td>
              </tr>
            <?php endforeach?>
            </tbody>
    

    step2:函数处理所有文章页面中的时间显示

    1.用函数去格式化时间

    // 用函数去处理时间
    function convert_date ($created) {
      // 数据库中存储的时间 '2017-07-01 08:08:00' 
      //格式化成 => '2017年07月01日 08:08:00
      // 如果配置文件没有配置时区
      // date_default_timezone_set('PRC');
      $timestamp = strtotime($created);
      return date('Y年m月d日<b
    >H:i:s', $timestamp);
    }
    
    1. 在时间的标签中用函数的方式去显示对应的时间
    <td class="text-center"><?php echo convert_date($item['created']); ?></td>
    

    step3:函数处理所有文章页面中的状态显示

    1. 用函数去处理状态
    // 用函数去处理状态
    function convert_status($status){
      $dict = array(
        'published' => '已发布',
        'drafted' => '草稿',
        'trashed' => '回收站'
        );
      return isset($dict[$status]) ? $dict[$status] : '未知';
    }
    
    1. 在状态的标签中用函数的方式去显示对应的状态
    <td class="text-center"><?php echo convert_status($item['status']); ?></td>
    

    step4:函数处理所有文章页面中的作者和分类显示

    1. 用函数去处理作者和分类
    //php部分
    //用函数去处理作者和分类方法一
    function get_user($user_id){
       return mysql_one ("select nickname from users where id = {$user_id}['nickname']");
     }
     function get_category($category_id){
       return mysql_one ("select name from categories where id = {$category_id}['name']");
     }
    
    1. 在分类和作者的标签中用函数的方式去显示对应的作者和分类
    //Html部分
    //用函数去处理作者和状态
    <td><?php  echo get_user($item['user_id']); ?></td>
    <td><?php  echo get_category($item['category_id']); ?></td> 
    

    step5:用关联数据库的方式去处理所有文章页面中的作者和分类显示(减少数据库的查询次数)

    1. 关联查询的方式介绍
      1.1 关联查询 posts 表与 categories
      查询总条数 = posts的总条数 * categories的总条数
      24 = 4 * 6
      在这里插入图片描述
      1.2 带有条件的关联查询
      在这里插入图片描述
      1.3 带有多个条件的关联查询
      在这里插入图片描述
      1.4 带有多个条件并查询多张表
      在这里插入图片描述
      1.5
      如果这几个表中有相同名称的字段,在查询过后转换为关联数组就会有问题(关联数组 的键是不能重复的),所以我们需要指定需要查询的字段,同时还可以给每一个字段起一个别名,避免冲突分别给 users.nickname categories.name 起别名
      users.nickname ==> user_name
      categoies.name == > category_name
      在这里插入图片描述
    2. 关联查询的方式使用
      2.1 将之前的查询语句改更改成关联查询的语句
    //php部分
    $posts = mysql_all('select 
    posts.id,
    posts.title,
    posts.created,
    posts.status,
    users.nickname as user_name,
    categories.name as category_name
    from posts
    inner join categories on posts.category_id = categories.id
    inner join users on posts.user_id = users.id');
    

    2.2 更改html部分

    //html部分
     <td><?php echo $item['user_name']; ?></td>
     <td><?php echo $item['category_name']; ?></td>
    

    step6: 实现页面呈现多页数据

    想要是实现分页的话,posts表中的数据显然不够做这个功能,所以需要导入更多的测试数据

    1. 复制 post-test-data.sql 文件代码 在数据库新建查询中粘贴,在代码末尾加上 commit; 然后点击运行
      在这里插入图片描述
      可以看到 posts 表中新增了很多数据
      在这里插入图片描述

    step7 : 分页加载文章数据

    1. 查询一部分数据
      1.1 当数据过多过后,如果还是按照以上操作每次查询全部数据,页面就显得十分臃肿,加载起来也非常慢,所以必须 要通过分页加载的方式改善(每次只显示一部分数据)。
      操作方式也非常简单,就是在原有 SQL 语句的基础之上加上 limit order by 子句
      在这里插入图片描述
      1.2 imit 用法:limit [offset, ]rows
      limit 10 -----只取前 10 条数据
      limit 5, 10 ----- 从第 5 条之后,第 6 条开始,向后取 10 条数据

    step8 : 分页参数计算

    limit 子句中的 0 和 10 不是一成不变的,应该跟着页码的变化而变化,具体的规则就是:
    第 1 页 limit 0, 10
    第 2 页 limit 10, 10
    第 3 页 limit 20, 10
    第 4 页 limit 30, 10 ...
    根据以上规则得出公式: offset = (page - 1) * size

    // 处理分页参数
    $size = 5;
    // // 计算越过多少条
    $offset = ($page - 1) * $size;
    // 用关联数据中方式去查询数据库
    // 获取全部数据
    $posts = mysql_all("select
      posts.id,
      posts.title,
      users.nickname as user_name,
      categories.name as category_name,
      posts.created,
      posts.status
      from posts
      inner join categories on posts.category_id = categories.id
      inner join users on posts.user_id = users.id
      order by posts.created desc
      limit {$offset}, {$size};
      ");
    

    step9 : 获取当前页码

    一般分页都是通过 URL 传递一个页码参数
    也就是说,我们应该在页面开始执行的时候获取这个 URL 参数

    //// 获取分页参数 没有或传过来的不是数字的话默认为 1 $page = isset($_GET['p']) && is_numeric($_GET['p'
    $page = empty($_GET['page']) ? 1 : (int)$_GET['page'];
    

    step 10 : 处理页面页码显示高亮并与地址栏同步

    //Php部分
    // 计算页码
    $visiables = 5;
    $region = ($visiables -1) / 2;
    $begin = $page - $region;
    $end = $page + $region;
    
    //Html部分
       <ul class="pagination pagination-sm pull-right">
              <li><a href="#">上一页</a></li>
              <?php for ($i = $begin; $i <= $end; $i++): ?>
              <li<?php echo $i === $page ? ' class="active"' : '' ?>><a href="?page=<?php echo $i ;?>"><?php echo $i; ?></a></li>
              <?php endfor ?>
              <li><a href="#">下一页</a></li>
       </ul>
    
    

    step 11. 处理页面分页最大和最小页码限制

    
    // 计算页码开始
    $visiables = 5;
    $region = ($visiables - 1) / 2; // 左右区间
    $begin = $page - $region; // 开始页码
    // $end = $page + $region;
    $end = $begin + $visiables; // 结束页码 + 1
    //出现$begin不合理的情况处理
    //$begin必须大于1
    if ($begin < 1) {
      $begin = 1;
      // begin 修改意味着必须要改 end
      $end = $begin + $visiables;
    }
    //$end不得超过最大page
    //求出最大页码
    $total_count = (int)mysql_one('select count(1) as num from posts;')['num'];
    $total_pages = (int)ceil($total_count / $size);
    // 判断
    if ($end > $total_pages + 1) {
      // end 超出范围
      $end = $total_pages + 1;
      // end 修改意味着必须要改 begin
      $begin = $end - $visiables;
      if ($begin < 1) {
        $begin = 1;
      }
    }
    
    //html部分,与上面不同的是
    //将for ($i = $begin; $i <= $end; $i++)更改成 for ($i = $begin; $i < $end; $i++)
    <li>
    <a href="#">上一页</a></li>
    <?php for ($i = $begin; $i < $end; $i++): ?>
    <li<?php echo $i === $page ? ' class="active"' : ''; ?>><a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a></li>
    <?php endfor ?>
    <li><a href="#">下一页</a>
    </li>
    

    step 12 : 解决step11中的bug

    1. bug1 : 到50的时候就不能显示高亮(原因,因为50以后就是小数float,要取整数)
      解决办法一:将小数类型强制转换成整数类型
      之前代码
    $total_pages = ceil($total_count / $size);
    

    修改后的代码

    $total_pages = (int)ceil($total_count / $size);
    

    解决办法二:将三个 === 更改成 两个 == (让它变得没有那么严谨)

    <li<?php echo $i == $page ? ' class="active"' : ''; ?>><a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a></li>
    
    1. bug2 : 当点击最后一个页码时,会报错
      在这里插入图片描述
      解决办法:
      将:
    //$end不得超过最大page
    //求出最大页码
    $total_count = (int)mysql_one('select count(1) as num from posts;')['num'];
    $total_pages = (int)ceil($total_count / $size);
    

    更改成:

    //$end不得超过最大page
    //求出最大页码
    $total_count = (int)mysql_one('select count(1) as num 
      from posts
      inner join categories on posts.category_id = categories.id
      inner join users on posts.user_id = users.id;')['num'];
    $total_pages = (int)ceil($total_count / $size);
    

    step 13 : 处理筛选分类,显示对应的分类页面

    // 分类筛选
     if(!empty($_GET['category'])){
      $where .= ' and posts.category_id = ' . $_GET['category'];
    }
    //防止category=all时报错,所以更改成
    if (isset($_GET['category']) && $_GET['category'] !== 'all') {
      $where .= ' and posts.category_id = ' . $_GET['category'];
    }
    
    
    //HTML部分 利用foreach遍历循环得到的categories表中的数据并呈现在页面上
    //给form表单设置action,表单自动默认method = "get",此处应该使用get方式
    //所以可以不用设置method
    <form class="form-inline" action="<?php echo $_SERVER['PHP_SELF']; ?>">
    //给select加上name属性
    <select  name="category" class="form-control input-sm">
       //给所有分类添加一个value="all",用来默认显示所有分类
       <option value="all">所有分类</option>
       //将未分类删掉,遍历循环categories表中数据
       //<option value="">未分类</option>
       <?php foreach ($categories as $item): ?>
       //给分类的option添加value = "id" ,用来作为筛选的标识
       //再加上一个判断当前是否存在$_GET['category'],用来判断当前所选项,记住筛选状态,并展示在框内
       <option value="<?php echo $item['id']; ?>"<?php echo isset($_GET['category']) && $_GET['category'] == $item['id'] ? ' selected' : '' ?>>
        <?php echo $item['name']; ?>
        </option>
        <?php endforeach ?>  
     </select>
    

    step 14 : 处理筛选状态,显示对应的状态页面

    //PHP部分
    //筛选状态
    if (isset($_GET['status']) && $_GET['status'] !== 'all') {
      $where .= " and posts.status = '{$_GET['status']}'";
    }
    
    
    //HTML部分
    //给每一个option标签都加上对应的value属性
    //并且判断是否存在$_GET['status'],用来判断当前所选项,记住筛选状态,并展示在框内
    <select name="status" class="form-control input-sm">
        <option value="all">所有状态</option>
        <option value="drafted"<?php echo isset($_GET['status']) && $_GET['status'] == 'drafted' ? ' selected' : '' ?>>草稿</option>
        <option value="published"<?php echo isset($_GET['status']) && $_GET['status'] == 'published' ? ' selected' : '' ?>>已发布</option>
        <option value="trashed"<?php echo isset($_GET['status']) && $_GET['status'] == 'trashed' ? ' selected' : '' ?>>回收站</option>
    </select>
    
    

    step 15 : 根据筛选的参数,显示筛选数据的页面

    当我们加上 where 语句时,可实现数据的筛选,where语句筛选数据都是根据数据的唯一标识(也就是id)来进行筛选

    在这里插入图片描述
    所以,在之前的每一项查询中添加 where 子句

    //sql语句的注入
    // 数据库查询筛选条件(默认为 1 = 1,相当于没有条件) 
    $where = '1 = 1';
    
    $posts = mysql_all("select
      posts.id,
      posts.title,
      users.nickname as user_name,
      categories.name as category_name,
      posts.created,
      posts.status
      from posts
      inner join categories on posts.category_id = categories.id
      inner join users on posts.user_id = users.id
      where {$where}
      order by posts.created desc
      limit {$offset}, {$size};
      ");
    
    $total_count = (int)mysql_one("select count(1) as num from posts
    inner join categories on posts.category_id = categories.id
    inner join users on posts.user_id = users.id
    where {$where};")['num'];
    $total_pages = (int)ceil($total_count / $size);
    

    step 16 : 根据筛选的数据显示完整的 url 地址

    ///Php部分
    //定义一个serch 
    $search = '';
    //在每个筛选下加上serch
    // 分类筛选
     // if(!empty($_GET['category'])){
    if (isset($_GET['category']) && $_GET['category'] !== 'all') {
      $where .= ' and posts.category_id = ' . $_GET['category'];
      $search .= '&category=' . $_GET['category'];
    }
    //筛选状态
    if (isset($_GET['status']) && $_GET['status'] !== 'all') {
      $where .= " and posts.status = '{$_GET['status']}'";
      $search .= '&status=' . $_GET['status'];
    }
    
    
    //Html部分
    //没有处理分类和状态显示所有分类和状态之前
    <li><a href="#">上一页</a></li>
        <?php for ($i = $begin; $i < $end; $i++): ?>
        <li<?php echo $i === $page ? ' class="active"' : ''; ?>><a href="?page=<?php echo $i; ?>">
        <?php echo $i; ?></a></li>
         <?php endfor ?>
    <li><a href="#">下一页</a></li>-->
    //处理分类和状态显示所有分类和状态之后
    <li><a href="#">上一页</a></li>
        <?php for ($i = $begin; $i < $end; $i++): ?>
         <li<?php echo $i == $page ? ' class="active"' : '' ?>><a href="?page=<?php echo $i . $search; ?>"><?php echo $i; ?></a></li>
        <?php endfor ?>
    <li><a href="#">下一页</a></li>
    

    step 17 : 如果用户在url地址中输入大于总页数的页码,则跳到最大页码

    if ($page > $total_pages) {
      // 跳转到第最后页
      header('Location: /admin/posts.php?page=' . $total_pages . $search);
    }
    

    step 18 : 文章中单条数据删除功能

    //Html部分
    <a href="/admin/post-delete.php?id=<?php echo $item['id']; ?>" class="btn btn-danger btn-xs">删除</a>
    

    新增一个 post-delete.php 文件与 category-delete.php 类似

    post-delete.php

    <?php
    /**
     * 根据客户端传递过来的ID删除对应数据
     */
    require_once '../functions.php';
    if (empty($_GET['id'])) {
      exit('缺少必要参数');
    }
    // $id = (int)$_GET['id'];
    $id = $_GET['id'];
    $rows = mysql_change('delete from posts where id in (' . $id . ');');
    header('Location: ' . $_SERVER['HTTP_REFERER']);
    
    // http 中的 referer 用来标识当前请求的来源
    //末尾这句话的作用是为了当用户删除最后一页数据时,不会报错,返回的是倒数第二页,显示正确
    

    posts.php完整代码

    <?php
    header("Content-Type: text/html;charset=utf-8");
    require_once '../functions.php';
    get_userinfo();
    // 处理分页参数
    $page = empty($_GET['page']) ? 1 : (int)$_GET['page'];
    $size = 20;
    // 计算出越过多少条
    $offset = ($page - 1) * $size;
    // 接收筛选数据
    $where = '1 = 1';
    $search = '';
    // 分类筛选
    if (isset($_GET['category']) && $_GET['category'] !== 'all') {
      $where .= ' and posts.category_id = ' . $_GET['category'];
      $search .= '&category=' . $_GET['category'];
    }
    //筛选状态
    if (isset($_GET['status']) && $_GET['status'] !== 'all') {
      $where .= " and posts.status = '{$_GET['status']}'";
      $search .= '&status=' . $_GET['status'];
    }
    // 用关联数据中方式去查询数据库
    // 获取全部数据
    $posts = mysql_all("select
      posts.id,
      posts.title,
      users.nickname as user_name,
      categories.name as category_name,
      posts.created,
      posts.status
      from posts
      inner join categories on posts.category_id = categories.id
      inner join users on posts.user_id = users.id
      where {$where}
      order by posts.created desc
      limit {$offset}, {$size};
      ");
    
    // 处理分页页码===============================
    // 计算页码
    // 计算页码开始
    $visiables = 5;
    $region = ($visiables - 1) / 2; // 左右区间
    $begin = $page - $region; // 开始页码
    $end = $begin + $visiables; // 结束页码 + 1
    
    //出现$begin不合理的情况处理
    //$begin必须大于1
    if ($begin < 1) {
      $begin = 1;
      // begin 修改意味着必须要改 end
      $end = $begin + $visiables;
    }
    
    //$end不得超过最大page
    //求出最大页码
    $total_count = (int)mysql_one("select count(1) as num from posts
    inner join categories on posts.category_id = categories.id
    inner join users on posts.user_id = users.id
    where {$where};")['num'];
    $total_pages = (int)ceil($total_count / $size);
    // 判断
    if ($end > $total_pages + 1) {
      // end 超出范围
      $end = $total_pages + 1;
      // end 修改意味着必须要改 begin
      $begin = $end - $visiables;
      if ($begin < 1) {
        $begin = 1;
      }
    }
    if ($page > $total_pages) {
      // 跳转到第最后页
      header('Location: /admin/posts.php?page=' . $total_pages . $search);
    }
    
    // 用函数去处理状态
    function convert_status($status){
      $dict = array(
        'published' => '已发布',
        'drafted' => '草稿',
        'trashed' => '回收站'
        );
      return isset($dict[$status]) ? $dict[$status] : '未知';
    }
    // 用函数去处理时间,格式化时间
    function convert_date ($created) {
      // 如果配置文件没有配置时区
      // date_default_timezone_set('PRC');
      $timestamp = strtotime($created);
      return date('Y年m月d日<b
    >H:i:s', $timestamp);
    }
    $categories = mysql_all('select * from categories;');
    ?>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="utf-8">
      <title>Posts &laquo; Admin</title>
      <link rel="stylesheet" href="/static/assets/vendors/bootstrap/css/bootstrap.css">
      <link rel="stylesheet" href="/static/assets/vendors/font-awesome/css/font-awesome.css">
      <link rel="stylesheet" href="/static/assets/vendors/nprogress/nprogress.css">
      <link rel="stylesheet" href="/static/assets/css/admin.css">
      <script src="/static/assets/vendors/nprogress/nprogress.js"></script>
    </head>
    <body>
      <script>NProgress.start()</script>
      <div class="main">
        <?php include 'com/nav.php';?>
        <div class="container-fluid">
          <div class="page-title">
            <h1>所有文章</h1>
            <a href="post-add.php" class="btn btn-primary btn-xs">写文章</a>
          </div>
          <div class="page-action">
            <!-- show when multiple checked -->
            <a class="btn btn-danger btn-sm" href="javascript:;" style="display: none">批量删除</a>
            <form class="form-inline" action="<?php echo $_SERVER['PHP_SELF']; ?>" >
              <select  name="category" class="form-control input-sm">
                <option value="all">所有分类</option>
                <!-- <option value="">未分类</option> -->
                <?php foreach ($categories as $item): ?>
                <option value="<?php echo $item['id']; ?>"<?php echo isset($_GET['category']) && $_GET['category'] == $item['id'] ? ' selected' : '' ?>>
                  <?php echo $item['name']; ?>
                </option>
                <?php endforeach ?>
               
              </select>
              <select name="status" class="form-control input-sm">
                <option value="all">所有状态</option>
                <option value="drafted"<?php echo isset($_GET['status']) && $_GET['status'] == 'drafted' ? ' selected' : '' ?>>草稿</option>
                <option value="published"<?php echo isset($_GET['status']) && $_GET['status'] == 'published' ? ' selected' : '' ?>>已发布</option>
                <option value="trashed"<?php echo isset($_GET['status']) && $_GET['status'] == 'trashed' ? ' selected' : '' ?>>回收站</option>
              </select>
              <button class="btn btn-default btn-sm">筛选</button>
            </form>
            <ul class="pagination pagination-sm pull-right">
              <li><a href="#">上一页</a></li>
              <?php for ($i = $begin; $i < $end; $i++): ?>
              <li<?php echo $i == $page ? ' class="active"' : '' ?>><a href="?page=<?php echo $i . $search; ?>"><?php echo $i; ?></a></li>
              <?php endfor ?>
              <li><a href="#">下一页</a></li>
            </ul>
          </div>
          <table class="table table-striped table-bordered table-hover">
            <thead>
              <tr>
                <th class="text-center" width="40"><input type="checkbox"></th>
                <th>标题</th>
                <th>作者</th>
                <th>分类</th>
                <th class="text-center">发表时间</th>
                <th class="text-center">状态</th>
                <th class="text-center" width="100">操作</th>
              </tr>
            </thead>
            <tbody>
            <?php foreach ($posts as $item): ?>
             <tr>
                <td class="text-center"><input type="checkbox"></td>
                <td><?php echo $item['title']; ?></td>
                //用关联数据库的方式去处理作者和状态
                <td><?php echo $item['user_name']; ?></td>
                <td><?php echo $item['category_name']; ?></td>
                //用函数去处理时间
                <td class="text-center"><?php echo convert_date($item['created']); ?></td>
                // 用函数处理后显示状态 
                <td class="text-center"><?php echo convert_status($item['status']); ?></td>
                <td class="text-center">
                  <a href="javascript:;" class="btn btn-default btn-xs">编辑</a>
                  <!-- <a href="javascript:;" class="btn btn-danger btn-xs">删除</a> -->
                <a href="/admin/post-delete.php?id=<?php echo $item['id']; ?>" class="btn btn-danger btn-xs">删除</a>
                </td>
              </tr>
    
            <?php endforeach?>
            </tbody>
          </table>
        </div>
      </div>
     <?php $current_page='posts';?>
     <?php include 'com/sidebar.php';?>
      <script src="/static/assets/vendors/jquery/jquery.js"></script>
      <script src="/static/assets/vendors/bootstrap/js/bootstrap.js"></script>
      <script>NProgress.done()</script>
    </body>
    </html>
    
    
  • 相关阅读:
    简单图表分析(2/2)
    简单图表分析(1/2)
    juqery dragsort使用遇到的问题
    移动端实战总结
    CSS VS JS动画,哪个更快[译]
    HTML5移动端图片上传模块
    移动端使用rem适配及相关问题
    再谈vertical-align与line-height
    Javascript中的Promise
    Retina屏实现1px边框
  • 原文地址:https://www.cnblogs.com/Chinatsu/p/13822934.html
Copyright © 2020-2023  润新知