如何用bootstrap 4的样式和类来设计你的基本html表格

143 阅读4分钟

在数据可视化领域,仪表盘的外观和感觉是非常重要的,因为它可以帮助用户消化你在仪表盘中显示的洞察力。我们通常用彩色的图表和现代调色板来设计仪表盘,这是改善仪表盘风格的好方法,但表格也是仪表盘的重要元素,需要进行改造以使其具有吸引力。在闪亮的应用程序中,我们有默认的表格小部件和其他流行的小部件,如DT、reactable等。这些表格的默认外观并不那么令人印象深刻。在这篇文章中,我们将向你展示如何用bootstrap 4的样式和类来设计你的基本html表格。

我创建了一个用户定义的函数,名为tbl( ) ,用于实现带有表格的bootstrap 4类。该函数有四个参数,如下所示。

  • data 你想在表中显示的数据框架的名称。
  • index 行数。将作为表格中的第一列显示。你需要为序列号创建一个列。它可以有任何字符串或字体,如 。fas fa-star
  • namecol 表格的第二列。它可以是任何一列,你想在它旁边显示图标或图像。
  • nameicon 可选参数。包含图像链接的列的名称。

示例数据框架

df <- data.frame(
  col0 = c("fas fa-star", "01", "02"),
  nameicon = c("https://www.freepnglogos.com/uploads/bitcoin-png/bitcoin-all-about-bitcoins-9.png",
               "https://freepngimg.com/thumb/bitcoin/59549-cryptocurrency-money-bitcoin-gold-cash-free-photo-png-thumb.png",
               "https://freepngimg.com/thumb/bitcoin/59526-cryptocurrency-badge-bitcoin-gold-png-file-hd-thumb.png"),
  Name = c("Bitcoin", "Ripple", "Bitcoin cash"),
  `Market cap` = c("$146,169,768.00", "$56,169,768.00", "$446,569,768.00"),
  Price = c("$8,536.79", "$8,536.79", "$8,836.79"),
  Volume = c("$7,576,878.89", "$7,576,878.89", "$7,576,878.89"),
  Change = c("-1.22%", "-0.18%", "+1.21%"),
  check.names = FALSE
)

在下面的程序中,我们正在使用tbl(df, col0, Name, nameicon)

library(shiny)
library(dplyr)

tbl <- function(data, index, namecol, nameicon = NULL)  {
  
  temp <- list()
  index <- deparse(substitute(index))
  namecol <- deparse(substitute(namecol))
  
  if(!missing(nameicon)) {
    nameicon <- deparse(substitute(nameicon))
  }
  
  # Convert to Character
  col_names <- names(data)
  data[,col_names] <- lapply(data[,col_names] , as.character)
  
  # Loop over Rows
  for(i in 1:nrow(data)) {
    
    col0 = data[i,index]
    col1 = data[i,namecol]
    icon = data[i,nameicon]
    
    first2cols <-  list(
      
      tags$td(tags$div(
        class = "d-flex mt-2 border-right",
        tags$div(
          class = "box p-2 rounded",
          tags$span(
            class = ifelse(substr(col0,1,2)=="fa", paste(col0, "fa-lg text-primary px-2"),
                           "text-primary px-2 font-weight-bold"),
            ifelse(substr(col0,1,2)=="fa", '', col0)
          )
        )
      )),
      tags$td(tags$div(
        class = "d-flex flex-column",
        tags$div(
          class = "text-muted",
          namecol
        ),
        if(!is.null(nameicon)) {
          tags$div(
            class = "d-flex align-items-center",
            tags$div(tags$img(
              src = icon,
              alt = NA,
              class = "icons"
            )),
            tags$b(
              class = "pl-2",
              col1
            )
          ) } else {
            
            tags$div(
              tags$b(
                col1
              )
            ) 
          }
      ))
      
    )
    
    # Loop over Columns (ignoring index, name and icon columns)
    temp.col <- list()
    data2 <- data[!(names(data) %in% c(index, namecol, nameicon))]
    for(j in 1:ncol(data2)) {
      
      temp.col[[j]] <-
        tags$td(tags$div(
          class = "d-flex flex-column",
          tags$div(
            class = "text-muted",
            colnames(data2)[j]
          ),
          tags$div(tags$b(data2[i,j]))
        ))
      
    }
    temp[[i]] <- tags$tr(first2cols, temp.col)
    
  }
  
  tags$div(
    class = "bg-white table-responsive",
    tags$table(
      class = "table",
      tags$tbody(
        temp
      ))
  )
  
}


# Bootstrap 4
theme <- bslib::bs_theme(version = 4)

# UI
ui <- fluidPage(
  
  theme = theme,
  
  br(),
  
  htmltools::htmlDependency(name = "font-awesome",
                            version = "5.13.0",
                            src = "www/shared/fontawesome",
                            package = "shiny",
                            stylesheet = c("css/all.min.css", "css/v4-shims.min.css")),

  tags$style("@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    font-family: 'Poppins', sans-serif;
    font-size: 0.95rem
}

body {
    background-color: #f3f3f3
}

#starred {
    box-shadow: 3px 3px 10px #b5b5b5
}

.table div.text-muted {
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 0.3rem;
    margin-top: 0.3rem
}

.icons {
    object-fit: contain;
    width: 25px;
    height: 25px;
    border-radius: 50%
}

.graph img {
    object-fit: contain;
    width: 40px;
    height: 50px;
    transform: scale(2) rotateY(45deg)
}

.graph .dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 3px solid #fff;
    position: absolute;
    background-color: blue;
    box-shadow: 1px 1px 1px #a5a5a5;
    top: 25px
}

.graph .dot:after {
    background-color: #fff;
    content: '$9,999.00';
    font-weight: 600;
    font-size: 0.7rem;
    position: absolute;
    top: -25px;
    left: -20px;
    box-shadow: 1px 1px 2px #a5a5a5;
    border-radius: 2px
}

.font-weight-bold {
    font-size: 1.3rem
}

#ethereum {
    transform: scale(2) rotateY(45deg) rotateX(180deg)
}

#ripple {
    transform: scale(2) rotateY(10deg) rotateX(20deg)
}

#eos {
    transform: scale(2) rotateY(50deg) rotateX(190deg)
}

.table tr td {
    border: none
}

.red {
    color: #ff2f2f;
    font-weight: 700
}

.green {
    color: #1cbb1c;
    font-weight: 700
}

.labels,
.graph {
    position: relative
}

.green-label {
    background-color: #00b300;
    color: #fff;
    font-weight: 600;
    font-size: 0.7rem
}

.orange-label {
    background-color: #ffa500;
    color: #fff;
    font-weight: 600;
    font-size: 0.7rem
}

.border-right {
    transform: scale(0.6);
    border-right: 1px solid black !important
}

.box {
    transform: scale(1.5);
    background-color: #dbe2ff
}

#top .table tbody tr {
    border-bottom: 1px solid #ddd
}

#top .table tbody tr:last-child {
    border: none
}

select {
    background-color: inherit;
    padding: 8px;
    border-radius: 5px;
    color: #444;
    border: 1px solid #444;
    outline-color: #00f
}

.text-white {
    background-color: rgb(43, 159, 226);
    border-radius: 50%;
    font-size: 0.7rem;
    font-weight: 700;
    padding: 2px 3px
}

a:hover {
    text-decoration: none
}

a:hover .text-white {
    background-color: rgb(20, 92, 187)
}

::-webkit-scrollbar {
    width: 10px;
    height: 4px
}

::-webkit-scrollbar-thumb {
    background: linear-gradient(45deg, #999, #777);
    border-radius: 10px
}

@media(max-width:379px) {
    .d-lg-flex .h3 {
        font-size: 1.4rem
    }
}

@media(max-width:352px) {
    #plat {
        margin-top: 10px
    }
}"),
  
  
  fluidRow(
    
    tags$div(
      class = "container mt-5",
      tags$div(
        class = "d-lg-flex align-items-lg-center py-4",
        tags$div(
          class = "h3 text-muted",
          "Top Cryptocurrency Prices"
        )
      ),
      tags$div(
        id = "top",
        tbl(df, col0, Name, nameicon)
      )
    ))
)


# Server
server <- function(input, output, session) { }

# Run App
shinyApp(ui = ui, server = server)

条件性格式化

为 "change "列中的负号和正号分别着色,我们可以使用javascript进行有条件的格式化。在下面的代码中,我们正在格式化第6列td:nth-child(6) 。你可以根据你的数据框架来改变它。

jscode <- "var CONTROL_INTERVAL2 = setInterval(function(){
  
    $('table tbody td:nth-child(6) b').each(function() {
      const value = $(this).text().substr(0,1);
      if ( value == '-') {
        $(this).css('color', 'red');
      }
      else {
        $(this).css('color', 'green');
      }
      
    });
    
    clearInterval(CONTROL_INTERVAL2);

  }, 500);"
  

请看下面的完整代码

theme <- bslib::bs_theme(version = 4)

# UI
ui <- fluidPage(
  
  theme = theme,
  
  br(),
  
  htmltools::htmlDependency(name = "font-awesome",
                            version = "5.13.0",
                            src = "www/shared/fontawesome",
                            package = "shiny",
                            stylesheet = c("css/all.min.css", "css/v4-shims.min.css")),
  
  
  tags$script("

      Shiny.addCustomMessageHandler('closeWindow', function(data) {
        eval(data.message)
      });"
  ),
  
  tags$style("@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    font-family: 'Poppins', sans-serif;
    font-size: 0.95rem
}

body {
    background-color: #f3f3f3
}

#starred {
    box-shadow: 3px 3px 10px #b5b5b5
}

.table div.text-muted {
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 0.3rem;
    margin-top: 0.3rem
}

.icons {
    object-fit: contain;
    width: 25px;
    height: 25px;
    border-radius: 50%
}

.graph img {
    object-fit: contain;
    width: 40px;
    height: 50px;
    transform: scale(2) rotateY(45deg)
}

.graph .dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 3px solid #fff;
    position: absolute;
    background-color: blue;
    box-shadow: 1px 1px 1px #a5a5a5;
    top: 25px
}

.graph .dot:after {
    background-color: #fff;
    content: '$9,999.00';
    font-weight: 600;
    font-size: 0.7rem;
    position: absolute;
    top: -25px;
    left: -20px;
    box-shadow: 1px 1px 2px #a5a5a5;
    border-radius: 2px
}

.font-weight-bold {
    font-size: 1.3rem
}

#ethereum {
    transform: scale(2) rotateY(45deg) rotateX(180deg)
}

#ripple {
    transform: scale(2) rotateY(10deg) rotateX(20deg)
}

#eos {
    transform: scale(2) rotateY(50deg) rotateX(190deg)
}

.table tr td {
    border: none
}

.red {
    color: #ff2f2f;
    font-weight: 700
}

.green {
    color: #1cbb1c;
    font-weight: 700
}

.labels,
.graph {
    position: relative
}

.green-label {
    background-color: #00b300;
    color: #fff;
    font-weight: 600;
    font-size: 0.7rem
}

.orange-label {
    background-color: #ffa500;
    color: #fff;
    font-weight: 600;
    font-size: 0.7rem
}

.border-right {
    transform: scale(0.6);
    border-right: 1px solid black !important
}

.box {
    transform: scale(1.5);
    background-color: #dbe2ff
}

#top .table tbody tr {
    border-bottom: 1px solid #ddd
}

#top .table tbody tr:last-child {
    border: none
}

select {
    background-color: inherit;
    padding: 8px;
    border-radius: 5px;
    color: #444;
    border: 1px solid #444;
    outline-color: #00f
}

.text-white {
    background-color: rgb(43, 159, 226);
    border-radius: 50%;
    font-size: 0.7rem;
    font-weight: 700;
    padding: 2px 3px
}

a:hover {
    text-decoration: none
}

a:hover .text-white {
    background-color: rgb(20, 92, 187)
}

::-webkit-scrollbar {
    width: 10px;
    height: 4px
}

::-webkit-scrollbar-thumb {
    background: linear-gradient(45deg, #999, #777);
    border-radius: 10px
}

@media(max-width:379px) {
    .d-lg-flex .h3 {
        font-size: 1.4rem
    }
}

@media(max-width:352px) {
    #plat {
        margin-top: 10px
    }
}"),
  
  
  fluidRow(
    
    tags$div(
      class = "container mt-5",
      tags$div(
        class = "d-lg-flex align-items-lg-center py-4",
        tags$div(
          class = "h3 text-muted",
          "Top Cryptocurrency Prices"
        )
      ),
      tags$div(
        id = "top",
        tbl(df, col0, Name, nameicon)
      )
    ))
)


# Server
server <- function(input, output, session) { 

  session$sendCustomMessage(type = "closeWindow", list(message = jscode))
  
}

# Run App
shinyApp(ui = ui, server = server)

在服务器中运行表

一般来说,我们需要将反应式数据框架传递给表格。因此,在shiny应用程序代码的服务器部分运行表格是很关键的。我们可以使用renderUI( )uiOutput( ) 来完成这个任务。请看下面的演示。

library(shiny)
library(dplyr)

df <- data.frame(
    col0 = c("fas fa-star", "01", "02"),
    nameicon = c("https://www.freepnglogos.com/uploads/bitcoin-png/bitcoin-all-about-bitcoins-9.png",
                 "https://freepngimg.com/thumb/bitcoin/59549-cryptocurrency-money-bitcoin-gold-cash-free-photo-png-thumb.png",
                 "https://freepngimg.com/thumb/bitcoin/59526-cryptocurrency-badge-bitcoin-gold-png-file-hd-thumb.png"),
    Name = c("Bitcoin", "Ripple", "Bitcoin cash"),
    `Market cap` = c("$146,169,768.00", "$56,169,768.00", "$446,569,768.00"),
    Price = c("$8,536.79", "$8,536.79", "$8,836.79"),
    Volume = c("$7,576,878.89", "$7,576,878.89", "$7,576,878.89"),
    Change = c("-1.22%", "-0.18%", "+1.21%"),
    check.names = FALSE
    )

jscode <- "var CONTROL_INTERVAL2 = setInterval(function(){
  
    $('#mytable table tbody td:nth-child(6) b').each(function() {
      const value = $(this).text().substr(0,1);
      if ( value == '-') {
        $(this).css('color', 'red');
      }
      else {
        $(this).css('color', 'green');
      }
      
    });
    
    clearInterval(CONTROL_INTERVAL2);
    
  }, 500);"


tbl <- function(data, index, namecol, nameicon = NULL)  {

temp <- list()
index <- deparse(substitute(index))
namecol <- deparse(substitute(namecol))

if(!missing(nameicon)) {
  nameicon <- deparse(substitute(nameicon))
}

# Convert to Character
col_names <- names(data)
data[,col_names] <- lapply(data[,col_names] , as.character)

# Loop over Rows
for(i in 1:nrow(data)) {

  col0 = data[i,index]
  col1 = data[i,namecol]
  icon = data[i,nameicon]
  
  first2cols <-  list(
    
    tags$td(tags$div(
      class = "d-flex mt-2 border-right",
      tags$div(
        class = "box p-2 rounded",
        tags$span(
          class = ifelse(substr(col0,1,2)=="fa", paste(col0, "fa-lg text-primary px-2"),
                         "text-primary px-2 font-weight-bold"),
          ifelse(substr(col0,1,2)=="fa", '', col0)
        )
      )
    )),
    tags$td(tags$div(
      class = "d-flex flex-column",
      tags$div(
        class = "text-muted",
        namecol
      ),
      if(!is.null(nameicon)) {
      tags$div(
        class = "d-flex align-items-center",
        tags$div(tags$img(
          src = icon,
          alt = NA,
          class = "icons"
        )),
        tags$b(
          class = "pl-2",
          col1
        )
      ) } else {
       
        tags$div(
          tags$b(
            col1
          )
        ) 
      }
    ))
    
    )
    
    # Loop over Columns (ignoring index, name and icon columns)
    temp.col <- list()
    data2 <- data[!(names(data) %in% c(index, namecol, nameicon))]
    for(j in 1:ncol(data2)) {
    
      temp.col[[j]] <-
      tags$td(tags$div(
      class = "d-flex flex-column",
      tags$div(
        class = "text-muted",
        colnames(data2)[j]
      ),
      tags$div(tags$b(data2[i,j]))
    ))
    
    }
    temp[[i]] <- tags$tr(first2cols, temp.col)
  
}

tags$div(
  class = "bg-white table-responsive",
  tags$table(
    class = "table",
    tags$tbody(
      temp
    ))
  )

}


# Bootstrap 4
theme <- bslib::bs_theme(version = 4)

# UI
ui <- fluidPage(
  
  theme = theme,
  
  br(),
  
  htmltools::htmlDependency(name = "font-awesome",
                            version = "5.13.0",
                            src = "www/shared/fontawesome",
                            package = "shiny",
                            stylesheet = c("css/all.min.css", "css/v4-shims.min.css")),
  
  
  tags$script("

      Shiny.addCustomMessageHandler('closeWindow', function(data) {
        eval(data.message)
      });"
  ),
  
  tags$style("@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    font-family: 'Poppins', sans-serif;
    font-size: 0.95rem
}

body {
    background-color: #f3f3f3
}

#starred {
    box-shadow: 3px 3px 10px #b5b5b5
}

.table div.text-muted {
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 0.3rem;
    margin-top: 0.3rem
}

.icons {
    object-fit: contain;
    width: 25px;
    height: 25px;
    border-radius: 50%
}

.graph img {
    object-fit: contain;
    width: 40px;
    height: 50px;
    transform: scale(2) rotateY(45deg)
}

.graph .dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 3px solid #fff;
    position: absolute;
    background-color: blue;
    box-shadow: 1px 1px 1px #a5a5a5;
    top: 25px
}

.graph .dot:after {
    background-color: #fff;
    content: '$9,999.00';
    font-weight: 600;
    font-size: 0.7rem;
    position: absolute;
    top: -25px;
    left: -20px;
    box-shadow: 1px 1px 2px #a5a5a5;
    border-radius: 2px
}

.font-weight-bold {
    font-size: 1.3rem
}

#ethereum {
    transform: scale(2) rotateY(45deg) rotateX(180deg)
}

#ripple {
    transform: scale(2) rotateY(10deg) rotateX(20deg)
}

#eos {
    transform: scale(2) rotateY(50deg) rotateX(190deg)
}

.table tr td {
    border: none
}

.red {
    color: #ff2f2f;
    font-weight: 700
}

.green {
    color: #1cbb1c;
    font-weight: 700
}

.labels,
.graph {
    position: relative
}

.green-label {
    background-color: #00b300;
    color: #fff;
    font-weight: 600;
    font-size: 0.7rem
}

.orange-label {
    background-color: #ffa500;
    color: #fff;
    font-weight: 600;
    font-size: 0.7rem
}

.border-right {
    transform: scale(0.6);
    border-right: 1px solid black !important
}

.box {
    transform: scale(1.5);
    background-color: #dbe2ff
}

#top .table tbody tr {
    border-bottom: 1px solid #ddd
}

#top .table tbody tr:last-child {
    border: none
}

select {
    background-color: inherit;
    padding: 8px;
    border-radius: 5px;
    color: #444;
    border: 1px solid #444;
    outline-color: #00f
}

.text-white {
    background-color: rgb(43, 159, 226);
    border-radius: 50%;
    font-size: 0.7rem;
    font-weight: 700;
    padding: 2px 3px
}

a:hover {
    text-decoration: none
}

a:hover .text-white {
    background-color: rgb(20, 92, 187)
}

::-webkit-scrollbar {
    width: 10px;
    height: 4px
}

::-webkit-scrollbar-thumb {
    background: linear-gradient(45deg, #999, #777);
    border-radius: 10px
}

@media(max-width:379px) {
    .d-lg-flex .h3 {
        font-size: 1.4rem
    }
}

@media(max-width:352px) {
    #plat {
        margin-top: 10px
    }
}"),
  
  
  fluidRow(
    
    tags$div(
      class = "container mt-5",
      tags$div(
        class = "d-lg-flex align-items-lg-center py-4",
        tags$div(
          class = "h3 text-muted",
          "Top Cryptocurrency Prices"
        )
      ),
      tags$div(
        id = "top",
        uiOutput('mytable')
        )
      ))
  )


# Server
server <- function(input, output, session) { 
  
  output$mytable <- renderUI({
    
    tbl(df, col0, Name, nameicon)
    
  })
  
  
  session$sendCustomMessage(type = "closeWindow", list(message = jscode))
  
  }

# Run App
shinyApp(ui = ui, server = server)