【问题标题】:How to output multicolumn html without "widows"?如何在没有“寡妇”的情况下输出多列 html?
【发布时间】:2010-04-23 01:00:56
【问题描述】:

我需要在 HTML 中输出恰好三列文本中的分类链接列表。它们的显示方式必须类似于报纸或杂志中的专栏。因此,例如,如果总共有 20 行,则第一列和第二列将包含 7 行,最后一列将包含 6 行。列表必须是动态的;它将定期更改。

棘手的部分是链接是用标题分类的,这个标题不能是“寡妇”。如果你有页面布局背景,你就会知道这意味着标题不能显示在列的底部——它们下面必须至少有一个链接,否则它们应该会碰到下一列(我知道,从技术上讲如果我实际上是在做页面布局,它应该是两行,但在这种情况下,一行是可以接受的)。我很难弄清楚如何完成这项工作。

这是我的意思的一个例子:

购物链接 3 Link1 链接 1 链接 4 链接 2 链接 2 链接 3 链接 3 汽车 链接 1 音乐 游戏链接 2 链接 1 链接 1 链接 2 新闻

如您所见,“新闻”标题位于中间列的底部,“寡妇”也是如此。这是无法接受的。我可以将它撞到下一列,但这会在第二列的底部产生不必要的大量空白。相反,整个列表需要重新平衡。

我想知道是否有人对如何完成此操作有任何提示,或者可能是源代码或插件。Python 更可取,但任何语言都可以。我只是想把一般概念弄下来。

【问题讨论】:

  • 这看起来与我知道的其他页面布局算法相似。我们可以改变盒子的高度吗?如果我们少一行,那么这些词“正好适合”,底部没有多余的空间。另外,我们是否更喜欢最后一列的空格而不是其他列的空格?

标签: html algorithm page-layout


【解决方案1】:

一般的要点是建立一个所有“可流动”项目(包括类别)的主列表,然后遍历列表,根据需要调整每列的行,以便没有类别保持寡头(或您可能有的任何其他条件。 )

Module Module1

    Dim Categories As New Dictionary(Of String, List(Of String))

    Sub Main()

        Const Columns As Integer = 3

        ' create the category items
        Dim ShoppingList As New List(Of String)
        Dim GamesList As New List(Of String)
        Dim CarsList As New List(Of String)
        Dim NewsList As New List(Of String)
        Dim MusicList As New List(Of String)

        ShoppingList.Add("Link1")
        ShoppingList.Add("Link2")
        ShoppingList.Add("Link3")

        GamesList.Add("Link1")
        GamesList.Add("Link2")
        GamesList.Add("Link3")
        GamesList.Add("Link4")

        CarsList.Add("Link1")
        CarsList.Add("Link2")

        NewsList.Add("Link1")
        NewsList.Add("Link2")
        NewsList.Add("Link3")

        MusicList.Add("Link1")

        ' create the categories
        Categories.Add("Shopping", ShoppingList)
        Categories.Add("Games", GamesList)
        Categories.Add("Cars", CarsList)
        Categories.Add("News", NewsList)
        Categories.Add("Music", MusicList)

        ' count each category and its items
        Dim TotalRows As Integer = Categories.Count
        For Each kvp As KeyValuePair(Of String, List(Of String)) In Categories
            TotalRows += kvp.Value.Count
        Next

        ' add a space between each category
        TotalRows += (Categories.Count - 1)

        ' determine the number of rows per column
        Dim RowsPerColumn As Integer = Int(TotalRows / Columns) + If((TotalRows Mod Columns) > 0, 1, 0)

        ' build a master list
        Dim master As New List(Of String)
        For Each kvp As KeyValuePair(Of String, List(Of String)) In Categories
            master.Add(kvp.Key)
            For Each item As String In kvp.Value
                master.Add(item)
            Next
            master.Add(" ")
        Next

        ' remove the last invalid blank item
        master.RemoveAt(master.Count - 1)

        ' ensure that the RowsPerColumn'th-item in the list is not a category
        Dim adjusted As Boolean
        Do
            adjusted = False
            For i As Integer = 1 To master.Count - 1 Step RowsPerColumn - 1
                If Categories.Keys.Contains(master(i)) Then
                    RowsPerColumn += 1 ' adjust rows per column (could go up or down)
                    adjusted = True
                End If
            Next
        Loop While adjusted

        ' output resulting table
        Using sw As New IO.StreamWriter("test.htm")
            sw.WriteLine("<html>")
            sw.WriteLine("<body>")
            sw.WriteLine("<table cellspacing=""0"" cellpadding=""3"" border=""1"">")
            For j As Integer = 0 To RowsPerColumn - 1
                sw.WriteLine("<tr>")
                Dim columnCount As Integer = 0 ' columns written
                For i As Integer = j To master.Count - 1 Step RowsPerColumn
                    sw.WriteLine("<td>" & master(i) & "</td>")
                    columnCount += 1
                Next
                ' if the number of columns actually written was less than Columns constant
                If columnCount < Columns Then
                    For c As Integer = 0 To Columns - columnCount - 1
                        sw.WriteLine("<td>&nbsp;</td>")
                    Next
                End If
                sw.WriteLine("</tr>")
            Next
            sw.WriteLine("</table>")
            sw.WriteLine("</body>")
            sw.WriteLine("</html>")
        End Using

    End Sub

End Module

【讨论】:

  • 哇,多好的回答啊。非常感谢您抽出宝贵时间。非常有帮助。
猜你喜欢
  • 2013-08-30
  • 1970-01-01
  • 2022-06-12
  • 2011-08-26
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 2019-03-12
相关资源
最近更新 更多