【问题标题】:How do i get my data from mysql to behave我如何从 mysql 获取我的数据以表现
【发布时间】:2019-03-11 06:07:38
【问题描述】:

所以我想填充并显示一个 HTML 表格,即 2 列宽。但是,无论我尝试什么,我的数据总是粘在一起。

问题是,我实际上想将整个数据放入一个表中,并按起始字母排序。

这是我的代码:

<?php include_once 'Database/dbh.php'; ?>

<!DOCTYPE html>
<html>
    <body>
        <?php
        $fetch = "SELECT DISTINCT Kategori, LEFT(Kategori, 1) AS Letter FROM kategorier ORDER BY Kategori;";
        $result = mysqli_query($conn, $fetch);
        $resultCheck = mysqli_num_rows($result);

        if ($resultCheck > 0) {
            while ($row = mysqli_fetch_assoc($result)) {
                if (!isset($lastLetter) || $lastLetter != $row['Letter']) {
                    $lastLetter = $row['Letter'];
                    echo "<h2>", $row['Letter'], "</h2>";
                }
                echo "<table><tr><td>" . $row['Kategori'] . "</td></tr></table>";
            }
        }
        ?>      
    </body>
</html>

这是现在的图片:


这是我想要的样子:

【问题讨论】:

  • 您正在循环的每次迭代中创建一个全新的表。确定表格的设计方式,然后在脚本中相应地分解 html。
  • 我不认为我理解你@aynber。所以你要我先做表,然后把数据放进去?如果是这样的话,我已经尝试过了,但它似乎不起作用。
  • 那是正确的。您想先启动表格,然后在循环中创建单元格,然后再完成表格。如果您想为每个字母创建一个表格,则在字母更改时(在您当前的 if 检查范围内)进行检查以停止/启动表格。如果您希望每个表有一定数量的列(即 5 个单词将跨越 2 行中的 4 个单元格),则添加一个计数器以在达到某个数字时关闭并开始一行。

标签: php html mysql mysqli html-table


【解决方案1】:

很抱歉让您失望了,但解决方案比您想象的要复杂一些。如我所见,@aynber 已经提出了建议。所以,如果他写了一个答案,首先考虑他的答案是公平的。

建议

关于关注点分离:

现在让我先说,对于未来,您应该熟悉Separation of Concerns 原则。简单来说,以您的代码为例:始终将涉及访问数据库的代码(用于获取数据、更新等)与显示数据的代码(例如页面的 HTML 部分)分开。

这意味着,如果您需要从数据库中获取数据,请在网页顶部进行,并将其保存在数组中。然后只需在网页的 HTML 部分中使用这些数组,而不是像 mysqli_querymysqli_fetch_assoc 等一些与 db 相关的函数。为清楚起见,请参阅我提供的代码的 HTML 部分 ( “index.php”)。

这种方法的一大优势是,您可以将整个 php 代码从页面顶部移动到 php 函数或类方法中。然后,数组将只包含调用这些函数/方法产生的数据。

以上所有陈述的要点是什么?随心所欲地使用 php 代码和网页顶部的数据,并将结果保存在 php 数组中。数组最终应该具有这样的结构,网页的 HTML 部分的工作将非常简单:读取和显示数组元素。

所以不要将 HTML 代码与 db 相关的代码混在一起。如果你这样做,那么代码太难维护了。

关于从 PHP 打印客户端代码:

您应该记住的另一个重要约定是,不要使用 php 代码打印任何客户端代码。例如。不要使用像echo "&lt;table&gt;&lt;tr&gt;&lt;td&gt;"... 这样的语句。在这种echo 的情况下,只需将要呈现的内容保存到变量中,然后根据需要将它们显示在网页的 HTML 部分中。

关于准备好的语句:

如果你需要执行带参数的sql语句,那么使用prepared statements(而不是在这种情况下mysqli::query)。它们将保护您的代码免受最终的sql injections 的影响。为了完成,在这个答案的最后,我发布了一个 index.php 的示例,使用准备好的语句而不是 mysqli::query

问题解答:

步骤:

关于我准备的解决方案,它包括四个步骤:

  1. 从数据库中获取数据并将其保存到一个数组中 ($data)。
  2. 首先,创建第二个数组 ($formattedData)。然后遍历 $data 并将其项目保存到 $formattedData 中,以便它们可以很容易地显示在选定的 HTML 结构中(div 用于字母,table 用于类别)。
  3. 遍历$formattedData 并在每个字母的最后一个类别行中为每个缺少的类别附加一个带有null 的项目作为类别名称。抱歉,我在这里写了一句话,但是,如果您阅读了我的代码中的 cmets,您肯定会更好地理解我的意思。
  4. 通过遍历$formattedData 并读取其值,在页面的 HTML 部分显示数据。

当然,您可以根据需要优化 php 代码和/或将其分配到两三个函数中。然后你可以调用它们并将它们的返回值分配给$data$formattedData 变量。

注意:

如果您使用我的连接代码,请不要忘记将我的数据库凭据替换为您的。


index.php

<?php
require 'Database/dbh.php';

$sql = 'SELECT
            DISTINCT Kategori,
            LEFT(Kategori, 1) AS Letter
        FROM kategorier
        ORDER BY Kategori';

$result = mysqli_query($conn, $sql);

/*
 * Fetch all data at once, into an array like this:
 *
 *  Array
 *  (
 *      [0] => Array
 *          (
 *              [Kategori] => Artiskok
 *              [Letter] => A
 *          )
 *
 *      [1] => Array
 *          (
 *              [Kategori] => Asiatisk
 *              [Letter] => A
 *          )
 *
 *      [2] => Array
 *          (
 *              [Kategori] => Burger
 *              [Letter] => B
 *          )
 *
 *      [...] => [...]
 *
 *  )
 */
$data = mysqli_fetch_all($result, MYSQLI_ASSOC);

/*
 * Free the memory associated with the result. You should
 * always free your result when it is not needed anymore.
 *
 * @link http://php.net/manual/en/mysqli-result.free.php
 */
mysqli_free_result($result);

/*
 * Close the previously opened database connection. Not really needed because
 * the PHP engine closes the connection anyway when the PHP script is finished.
 *
 * @link http://php.net/manual/en/mysqli.close.php
 */
mysqli_close($conn);

/*
 * Iterate through the fetched data and save it into a new array, with a structure suited for the
 * required HTML display. To each letter, a list of category rows is assigned. The new array will
 * look like this, when the maximal number of categories per category row is 2:
 *
 *  Array
 *  (
 *      [A] => Array
 *          (
 *              [0] => Array
 *                  (
 *                      [0] => Aoiuoiiiu
 *                      [1] => Aqewroiuoiiu
 *                  )
 *
 *              [1] => Array
 *                  (
 *                      [0] => Artiskok
 *                      [1] => Asiatisk
 *                  )
 *
 *              [2] => Array
 *                  (
 *                      [0] => Azkajhsdfjkh
 *                  )
 *
 *          )
 *
 *      [B] => Array
 *          (
 *              [0] => Array
 *                  (
 *                      [0] => Bhaskdfhjkh
 *                      [1] => Biuzutt
 *                  )
 *
 *              [1] => Array
 *                  (
 *                      [0] => Burger
 *                  )
 *
 *          )
 *
 *      [...] => [...]
 *
 *  )
 */
$formattedData = [];

// The maximal number of categories per each category row.
$maximalNumberOfCategoriesPerCategoryRow = 2;

// The number of categories per current category row.
$numberOfCategoriesPerCurrentCategoryRow = 0;

// The index of a category row in the list of all category rows assigned to a letter.
$indexOfCurrentCategoryRow = 0;

foreach ($data as $item) {
    $letter = $item['Letter'];
    $category = $item['Kategori'];

    if (!array_key_exists($letter, $formattedData)) {
        /*
         * Assign an item with the current letter as key and an array as value.
         * The array holds all category rows for the current letter.
         */
        $formattedData[$letter] = [];

        // Reset.
        $indexOfCurrentCategoryRow = 0;

        // Reset.
        $numberOfCategoriesPerCurrentCategoryRow = 0;
    }

    // Append the current category to the current category row for the current letter.
    $formattedData[$letter][$indexOfCurrentCategoryRow][] = $category;

    // Increment.
    $numberOfCategoriesPerCurrentCategoryRow++;

    /*
     * If the maximal number of categories per category row is reached...
     *
     * @see "Modulo" operator at https://secure.php.net/manual/en/language.operators.arithmetic.php
     */
    if (
            $numberOfCategoriesPerCurrentCategoryRow %
            $maximalNumberOfCategoriesPerCategoryRow === 0
    ) {
        // Reset.
        $numberOfCategoriesPerCurrentCategoryRow = 0;

        // Increment.
        $indexOfCurrentCategoryRow++;
    }
}

/*
 * Append an item with "null" as category for each missing category in the last
 * category row of each letter. The array holding the formatted data will look
 * like this, when the maximal number of categories per category row is 2:
 *
 *  Array
 *  (
 *      [A] => Array
 *          (
 *              [...] => [...]
 *
 *              [2] => Array
 *                  (
 *                      [0] => Azkajhsdfjkh
 *                      [1] => null
 *                  )
 *
 *          )
 *
 *      [B] => Array
 *          (
 *              [...] => [...]
 *
 *              [1] => Array
 *                  (
 *                      [0] => Burger
 *                      [1] => null
 *                  )
 *
 *          )
 *
 *      [...] => [...]
 *
 *  )
 */
foreach ($formattedData as $letter => $categoryRows) {
    $lastCategoryRow = end($categoryRows);
    $lastCategoryRowKey = key($categoryRows);

    $numberOfCategoriesPerLastCategoryRow = count($lastCategoryRow);

    $numberOfMissingCategoriesInLastCategoryRow = $maximalNumberOfCategoriesPerCategoryRow -
            $numberOfCategoriesPerLastCategoryRow;

    for ($i = 0; $i < $numberOfMissingCategoriesInLastCategoryRow; $i++) {
        // Append an item with "null" as category.
        $formattedData[$letter][$lastCategoryRowKey][] = null;
    }
}

//=====================================================================================
//@todo Just for testing: uncomment the next two lines to display the arrays on screen.
//=====================================================================================
//echo '<pre>' . print_r($data, TRUE) . '</pre>';
//echo '<pre>' . print_r($formattedData, TRUE) . '</pre>';
//=====================================================================================
?>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
        <meta charset="UTF-8" />
        <!-- The above 3 meta tags must come first in the head -->

        <title>Demo</title>

        <link href="custom.css" type="text/css" rel="stylesheet">
    </head>
    <body>

        <h3>
            Demo: Print a list of categories per category letter, on multiple columns.
        </h3>

        <?php
        if ($formattedData) { /* Data exists */
            foreach ($formattedData as $letter => $categoryRows) {
                ?>
                <div class="categories-container">
                    <div class="letter">
                        <?php echo $letter; ?>
                    </div>
                    <table class="categories">
                        <?php
                        foreach ($categoryRows as $categoryRow) {
                            ?>
                            <tr>
                                <?php
                                foreach ($categoryRow as $category) {
                                    ?>
                                    <td>
                                        <?php echo $category; ?>
                                    </td>
                                    <?php
                                }
                                ?>
                            </tr>
                            <?php
                        }
                        ?>
                    </table>
                </div>
                <?php
            }
        } else { /* No data */
            ?>
            <p class="no-data">
                No data found
            </p>
            <?php
        }
        ?>

    </body>
</html>

custom.css

body {
    margin: 0;
    padding: 20px;
    color: #333;
}

a {
    text-decoration: none;
}

.categories-container {
    margin-bottom: 10px;
}

.letter {
    padding: 10px;
    text-align: left;
    font-weight: 700;
    background-color: #a0c3e5;
}

.categories {
    width: 100%;
    border-spacing: 1px;
    border-collapse: separate;
}

.categories td {
    width: 50%;
    padding: 10px;
    background-color: #f4f4f4;
}

.no-data {
    padding: 10px;
    background-color: #f4f4f4;
}

数据库/dbh.php

<?php

/*
 * This page contains the code for creating a mysqli connection instance.
 */

// Db configs.
define('HOST', 'localhost');
define('PORT', 3306);
define('DATABASE', 'tests');
define('USERNAME', 'root');
define('PASSWORD', 'root');

// Error reporting.
error_reporting(E_ALL);
ini_set('display_errors', 1); /* SET IT TO 0 ON A LIVE SERVER! */

/*
 * Enable internal report functions. This enables the exception handling,
 * e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions
 * (mysqli_sql_exception).
 *
 * MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
 * MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings.
 *
 * @link http://php.net/manual/en/class.mysqli-driver.php
 * @link http://php.net/manual/en/mysqli-driver.report-mode.php
 * @link http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

// Create a new db connection.
$conn = mysqli_connect(HOST, USERNAME, PASSWORD, DATABASE, PORT);

用于测试的数据

CREATE TABLE `kategorier` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `Kategori` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `kategorier` (`id`, `Kategori`)
VALUES
    (1,'Artiskok'),
    (2,'Asiatisk'),
    (3,'Burger'),
    (4,'Pizza'),
    (5,'Asiatisk'),
    (6,'Artiskok'),
    (7,'Artiskok'),
    (8,'Durum'),
    (9,'Durum'),
    (10,'Pizza'),
    (11,'Chinaboks'),
    (12,'Azkajhsdfjkh'),
    (13,'Aoiuoiiiu'),
    (14,'Aqewroiuoiiu'),
    (15,'Bhaskdfhjkh'),
    (16,'Biuzutt');

结果


附加内容:

这是一个如何使用准备好的语句而不是mysqli::query 获取数据的示例。请注意,我只将数据获取代码放在这里。其余代码与上述index.php页面的omolog部分相同,使用mysqli::query

index.php

<?php

require 'Database/dbh.php';

/*
 * Save the values, with which the database data will be filtered, into variables.
 * These values will replace the parameter markers in the sql statement.
 * They can come, for example, from a POST request of a submitted form.
 */
$letterParam1 = 'A';
$letterParam2 = 'C';
$letterParam3 = 'P';

/*
 * The SQL statement to be prepared. Notice the so-called markers, e.g. the "?" signs. They
 * will be replaced later with the corresponding values when using mysqli_stmt::bind_param.
 *
 * @link http://php.net/manual/en/mysqli.prepare.php
 */
$sql = 'SELECT
            DISTINCT Kategori,
            LEFT(Kategori, 1) AS Letter
        FROM kategorier
        WHERE
            LEFT(Kategori, 1) = ?
            OR LEFT(Kategori, 1) = ?
            OR LEFT(Kategori, 1) = ?
        ORDER BY Kategori';

/*
 * Prepare the SQL statement for execution - ONLY ONCE.
 *
 * @link http://php.net/manual/en/mysqli.prepare.php
 */
$statement = mysqli_prepare($conn, $sql);

/*
 * Bind variables for the parameter markers (?) in the SQL statement that was passed to prepare().
 * The first argument of bind_param() is a string that contains one or more characters which
 * specify the types for the corresponding bind variables.
 *
 * @link http://php.net/manual/en/mysqli-stmt.bind-param.php
 */
mysqli_stmt_bind_param($statement, 'sss'
        , $letterParam1
        , $letterParam2
        , $letterParam3
);

/*
 * Execute the prepared SQL statement. When executed any parameter markers
 * which exist will automatically be replaced with the appropriate data.
 *
 * @link http://php.net/manual/en/mysqli-stmt.execute.php
 */
mysqli_stmt_execute($statement);

/*
 * Get the result set from the prepared statement.
 *
 * NOTA BENE:
 *
 * Available only with mysqlnd ("MySQL Native Driver")! If this is not installed, then
 * uncomment "extension=php_mysqli_mysqlnd.dll" in PHP config file (php.ini) and restart
 * web server (I assume Apache) and mysql service. Or use the following functions instead:
 * mysqli_stmt::store_result + mysqli_stmt::bind_result + mysqli_stmt::fetch.
 *
 * @link http://php.net/manual/en/mysqli-stmt.get-result.php
 * @link https://stackoverflow.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result
 */
$result = mysqli_stmt_get_result($statement);

/*
 * Fetch all data at once, into an array like this:
 *
 *  Array
 *  (
 *      [0] => Array
 *          (
 *              [Kategori] => Artiskok
 *              [Letter] => A
 *          )
 *
 *      [1] => Array
 *          (
 *              [Kategori] => Asiatisk
 *              [Letter] => A
 *          )
 *
 *      [2] => Array
 *          (
 *              [Kategori] => Burger
 *              [Letter] => B
 *          )
 *
 *      [...] => [...]
 *
 *  )
 */
$data = mysqli_fetch_all($result, MYSQLI_ASSOC);

/*
 * Free the memory associated with the result. You should
 * always free your result when it is not needed anymore.
 *
 * @link http://php.net/manual/en/mysqli-result.free.php
 */
mysqli_free_result($result);

/*
 * Close the prepared statement. It also deallocates the statement handle.
 * If the statement has pending or unread results, it cancels them
 * so that the next query can be executed.
 *
 * @link http://php.net/manual/en/mysqli-stmt.close.php
 */
mysqli_stmt_close($statement);

/*
 * Close the previously opened database connection. Not really needed because
 * the PHP engine closes the connection anyway when the PHP script is finished.
 *
 * @link http://php.net/manual/en/mysqli.close.php
 */
mysqli_close($conn);

/*
 * ---------------------------------------------------------------------------------------------
 * The rest of the page is identical with the omolog part of index.php, which uses mysqli::query
 * ---------------------------------------------------------------------------------------------
 */

// ...

【讨论】:

  • 感谢您的帮助 :D 我还有一些问题。当我有 2 个东西/数据时,它将生成 4 行/列,而不是需要的 2 个。你能帮我实施准备好的陈述吗? :D
  • @MrSuckAlot 嗨。不客气。不幸的是,直到星期三,我都无法帮助您编写代码。那我给你写信。但请注意,我并不完全明白你在问什么。因此,在此之前,请花点时间进行更清晰、更详细的解释。
  • 我会努力的!
  • @MrSuckAlot 嗨。很抱歉,但我仍然无法按照承诺明天为您提供任何代码。我的电脑坏了,可能需要一个多星期才能修复它。
  • 没关系,我发现了代码的问题 :D 我现在唯一感兴趣的是保护 sql_injections 中的代码
【解决方案2】:

我建议不要使用 Table 元素,而是使用 Definition List 元素 dl,因为它的目的是您想要的显示结果。

不过,为了解决您的问题,我建议进行一些修改。 首先,请记住DISTINCT 适用于整个列列表,而不仅仅是它旁边的列。其次,来自 MySQL 的ORDER BY 通常比在 PHP 中按字母顺序排序要慢,并且 MySQL 不按字母数字值排序 naturally。最后,由于数据需要按字母顺序迭代以确定在移动到下一组之前要显示的第一个字母,因此实际上不需要在 MySQL 查询中使用 LEFT()

定义列表示例:https://3v4l.org/hETha

 $sql = 'SELECT DISTINCT Kategori FROM kategorier;';
 $result = mysqli_query($conn, $sql);
 if ($kategorier = mysqli_fetch_all($result, MYSQLI_ASSOC)) {
    //convert array of arrays to single array - PDO supports PDO::FETCH_GROUP|PDO::FETCH_COLUMN
    $kategorier = array_column($kategorier, 'Kategori');
    //sort the resulting array as a human would
    natsort($kategorier); 
 }
 $previousLetter = null;
 ?>
<dl>
 <?php 
 foreach ($kategorier as $kategori) {
     $currentLetter = strtoupper($kategori[0]);
     if ($previousLetter !== $currentLetter) { ?>
         <dt><h2><?php echo $currentLetter; ?></h2></dt>
     <?php  } ?>
     <dd><?php echo $kategori; ?></dd>
     <?php $previousLetter = $currentLetter; 
     } ?>      
 <dl>

表格数据:

Kategori
---------
Burger
Pizza
Pizza2
Pizza3
Chinaboks
Artiskok
Durum
Asiatisk
Asiatisk2
Asiatisk20
Asiatisk3

数据库结果:(MySQL 将按1, 10, 2, 20 排序,而不是1, 2, 10, 20

[
    ['Kategori' => 'Burger'],
    ['Kategori' => 'Pizza'],
    ['Kategori' => 'Pizza2'],
    ['Kategori' => 'Pizza3'],
    ['Kategori' => 'Chinaboks'],
    ['Kategori' => 'Artiskok'],
    ['Kategori' => 'Durum'],
    ['Kategori' => 'Asiatisk'],
    ['Kategori' => 'Asiatisk2'],
    ['Kategori' => 'Asiatisk20'],
    ['Kategori' => 'Asiatisk3'],
];

排序后的 PHP 数组结果:

[
    'Artiskok',
    'Artiskok2',
    'Artiskok3',
    'Artiskok20',
    'Asiatisk',
    'Burger',
    'Chinaboks',
    'Durum',
    'Pizza',
    'Pizza2',
    'Pizza3',
];

生成的 HTML 输出:

注意:使用float 将从左到右排序,即

1 | 2
3 | 4
5

/* Suggested CSS */
* {
  box-sizing: border-box;
}
dd {
  margin-left: 0;
  float: left;
  width: 50%;
}
dt {
  padding: 12px 0;
  clear: both;
}
<dl>
    <dt><h2>A</h2></dt>
    <dd>Artiskok</dd>
    <dd>Asiatisk</dd>
    <dd>Asiatisk2</dd>
    <dd>Asiatisk3</dd>
    <dd>Asiatisk20</dd>
    <dt><h2>B</h2></dt>
    <dd>Burger</dd>
    <dt><h2>C</h2></dt>
    <dd>Chinaboks</dd>
    <dt><h2>D</h2></dt>
    <dd>Durum</dd>
    <dt><h2>P</h2></dt>
    <dd>Pizza</dd>
    <dd>Pizza2</dd>
    <dd>Pizza3</dd>
<dl>

如果你想做更复杂的 CSS 样式,比如columns 排序。您可以改用嵌套列表。但是,最好在显示视图中迭代数据之前组织数据。

嵌套列表示例:https://3v4l.org/bAVGW

//...

$letters = [];
if (!empty($kategorier)) {
    $kategorier = array_column($kategorier, 'Kategori');
    //sort the resulting array as a human would
    natsort($kategorier); 

    foreach ($kategorier as $kategori) {
        $k = strtoupper($kategori[0]);
        if (!isset($letters[$k])) {
             $letters[$k] = [];
        }
        $letters[$k][] = $kategori;
    }
}
?>

<ul class="category-index">
<?php foreach ($letters as $k => $kategorier) { ?>
    <li>
        <h2><?php echo $k; ?></h2>
        <ul class="category">
        <?php foreach ($kategorier as $kategori) { ?>
            <li><?php echo $kategori; ?></li>
        <?php } ?>
        </ul>
    </li>
<?php } ?>
</ul>

HTML 输出结果:

注意:使用columns CSS 定义,将从左上到右下排序,即

1 | 4
2 | 5
3

/* Suggested CSS */

* {
  box-sizing: border-box;
}

ul.category-index ul,
ul.category-index {
  list-style: none;
  margin: 0;
  padding: 0;
}

ul.category-index li {
  padding: 0;
  margin: 0;
}

ul.category {
  columns: 2;
}
<ul class="category-index">
  <li>
    <h2>A</h2>
    <ul class="category">
      <li>Artiskok</li>
      <li>Asiatisk</li>
      <li>Asiatisk2</li>
      <li>Asiatisk3</li>
      <li>Asiatisk20</li>
    </ul>
  </li>
  <li>
    <h2>B</h2>
    <ul class="category">
      <li>Burger</li>
    </ul>
  </li>
  <li>
    <h2>C</h2>
    <ul class="category">
      <li>Chinaboks</li>
    </ul>
  </li>
  <li>
    <h2>D</h2>
    <ul class="category">
      <li>Durum</li>
    </ul>
  </li>
  <li>
    <h2>P</h2>
    <ul class="category">
      <li>Pizza</li>
      <li>Pizza2</li>
      <li>Pizza3</li>
    </ul>
  </li>
</ul>

至于您想要的table 元素用法。您可以使用包含以下 html 的嵌套列表示例 PHP 代码。但是,为了确保整个表是统一的,您将需要使用单个表。 colspan="2" 可用于类别索引行,将它们扩展到两列。为了确定何时需要新行,使用% 2,这将在类别的每次偶数迭代中发生。以及使用count 来确定是否需要将空表单元格添加到当前类别列表中,并避免创建额外的空表行。

表格示例:https://3v4l.org/ZuN20

//...    

$letters = [];
if (!empty($kategorier)) {
    $kategorier = array_column($kategorier, 'Kategori');
    //sort the resulting array as a human would
    natsort($kategorier); 

    foreach ($kategorier as $kategori) {
        $k = strtoupper($kategori[0]);
        if (!isset($letters[$k])) {
             $letters[$k] = [];
        }
        $letters[$k][] = $kategori;
    }
}
?>
<table>
    <tbody>
    <?php foreach($letters as $k => $kategorier) { ?>
        <tr>
           <td colspan="2"><h2><?php echo $k; ?></h2></td>
        </tr>
        <tr>
        <?php 
        $l = count($kategorier);
        if ($l & 1) {
           $kategorier[] = '';
           $l++;
        }
        $y = $l - 1;
        foreach ($kategorier as $i => $kategori) { ?>
            <td><?php echo $kategori; ?></td>
            <?php if ($i % 2 && $i !== $y) { ?></tr><tr><?php } ?>
        <?php } ?>
        </tr>
    <?php } ?>
    </tbody>
</table>

生成的 HTML:

注意:使用table 将从左到右排序。即

1 | 2
3 | 4
5 |

/* Example CSS */

* {
  box-sizing: border-box;
}

table {
  width: 100%;
}
<table>
  <tr>
    <td colspan="2">
      <h2>A</h2>
    </td>
  </tr>
  <tr>
    <td>Artiskok</td>
    <td>Asiatisk</td>
  </tr>
  <tr>
    <td>Asiatisk2</td>
    <td>Asiatisk3</td>
  </tr>
  <tr>
    <td>Asiatisk20</td>
    <td></td>
  </tr>
  <tr>
    <td colspan="2">
      <h2>B</h2>
    </td>
  </tr>
  <tr>
    <td>Burger</td>
    <td></td>
  </tr>
  <tr>
    <td colspan="2">
      <h2>C</h2>
    </td>
  </tr>
  <tr>
    <td>Chinaboks</td>
    <td></td>
  </tr>
  <tr>
    <td colspan="2">
      <h2>D</h2>
    </td>
  </tr>
  <tr>
    <td>Durum</td>
    <td></td>
  </tr>
  <tr>
    <td colspan="2">
      <h2>P</h2>
    </td>
  </tr>
  <tr>
    <td>Pizza</td>
    <td>Pizza2</td>
  </tr>
  <tr>
    <td>Pizza3</td>
    <td></td>
  </tr>
</table>

【讨论】:

  • 嗨。首先,很好的例子。我对您对以下内容的看法感兴趣。在“定义列表示例”和“表格示例”中,在 HTML 部分的foreach 循环中,您正在执行一些演示和决策逻辑。假设您正在遵循 MVC 方法,其中视图类负责表示逻辑并加载+渲染模板文件。对于每个上述示例,您是将代码放在视图类中还是保留在模板文件中?为什么选择?谢谢。
  • @dakis 这取决于很多因素,当严格使用MVC时,我将业务和模板逻辑分开,目的是减少代码重复。模型和模板都可以重复使用,并且每次使用时功能都相同。对我来说,包含 HTML 的模板就是视图。我个人的偏好是使用尽可能少的服务器端逻辑来渲染视图,依靠 CSS、Javascript 和 HTML 结构来完成渲染输出的所需显示和操作。
  • @dakis 最后,大多数新手在不使用框架的情况下无法有效地实现关注点分离。虽然它是最佳实践并且经常鼓励其他人也这样做,因为它使编程更大的项目更容易排除故障和操作,但它超出了程序编写问题的范围,并且通常只会让 OP 给他们更多的问题而不是他们正在寻找的答案。
  • 我问你我的问题只是出于个人原因;与OP问题无关。我试图想象自己,如果您在答案中使用的那种表示逻辑在某些情况下更适合应用于我的 mvc 项目。我的 mvc 有一个精确的工作流程和 SoC。但是我在您的回答中发现了一定的灵活性,这是我以前没有想到的。我很高兴你回答了我,因为现在我有所有的部分要考虑。再次感谢您。
  • @dakis 我还想指出,我更喜欢使用模板引擎而不是原始 HTML+PHP。例如,Twig 允许您轻松扩展、嵌入、包含和覆盖模板中的块/部分,这在普通 PHP 中不太可读。这使您可以灵活地添加或重用基本模板。连同每个模板的模板逻辑 SoC。 twigfiddle.com/0nl64v 更不用说最佳实践的实施了,比如从模型数据中自动转义 HTML 输出。
【解决方案3】:

更改为(未经测试):

while ($row = mysqli_fetch_assoc($result)) {
      if (!isset($lastLetter) || $lastLetter != $row['Letter']) {
            echo "</tr></table>";
            $lastLetter = $row['Letter'];
            echo "<h2>", $row['Letter'], "</h2>";
            echo "<table><tr>";
      }
      echo "<td>" . $row['Kategori'] . "</td>";

}

希望对你有所帮助;)

干杯

尼古拉斯

【讨论】:

    【解决方案4】:

    我建议您可以使用 Bootstrap 模板,并使用如下代码作为结果,结果将根据需要分成两列。

    echo "<div class="col-lg-6 col-md-6 col-sm-6"><table><tr><td>" . $row['Kategori'] . "</td></tr></table></div>";
    

    【讨论】:

    • 您的示例将创建表格列。使用 bootstrap 的网格系统,将不需要该表。此外,他只需要col-xs-650% 宽度列应用于所有视点,否则只需col-sm-6 允许xs 视点中的单列和sm 或更高视点中的50% 宽度。
    • 这取决于他,他想要怎样的结果。但无论如何感谢@fyrye 的评论。
    • 主要问题是您的示例没有演示 OP 如何显示字母分组以及各个类别。
    猜你喜欢
    • 2017-11-15
    • 1970-01-01
    • 2015-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多