将显示属性设置为“none”会删除超链接的目标。

3
我在构建R中的Shiny应用程序时遇到了这个问题。 在应用程序中,使用操作按钮来触发隐藏的下载按钮。 这样可以使我观察操作按钮事件,对该事件做出反应,然后触发下载过程。
但是,当我将下载按钮的display属性设置为hidden时,按钮的href目标(通常指向像"session/1c47..ef8/download/download_show?w="这样的东西)丢失了。
下面是一个更小的Shiny应用程序,重现了这个问题。
shinyApp(
  ui = fluidPage(
    tags$head(
      tags$style(HTML(".hide { display: none; }")),
      tags$script(HTML('
        Shiny.addCustomMessageHandler("trigger-button", function(message) {
          document.getElementById(message.button_id).click();
        });
      '))
    ),
    div(
      class = "disable",
      downloadButton("download_shown", "Shown"),
      div(
        class = "hide",
        downloadButton("download_hidden", "Hidden")
      )
    ),
    br(),
    actionButton("trigger_shown", "I can trigger the visible button!"),
    actionButton("trigger_hidden", "I can trigger the hidden button!")
  ),
  server = function(input, output, session) {
    output$download_shown <- downloadHandler(
      filename = "sample.txt",
      content = function(file) {
        cat("I'm visible!\n", file = file)
      }
    )

    output$download_hidden <- downloadHandler(
      filename = "sample2.txt",
      content = function(file) {
        cat("I'm hidden!\n", file = file)
      }
    )

    observeEvent(input$trigger_shown, {
      session$sendCustomMessage(
        "trigger-button",
        list(button_id = "download_shown")
      )
    })

    observeEvent(input$trigger_hidden, {
      session$sendCustomMessage(
        "trigger-button",
        list(button_id = "download_hidden")
      )
    })
  }
)

在应用程序中,两个操作按钮触发它们相应的下载按钮。点击可见的下载按钮会正确地下载文件sample.txt。点击隐藏的下载按钮会下载一个HTML文件,即网页,而不是sample2.txt文件。此外,如果检查生成的HTML,您会发现download_hidden下载按钮具有没有目标的href属性。
  • HTML规范中是否有任何规定隐藏元素不能有href目标?这似乎非常不可能,我搜索了很多也没有找到任何人或事情证实这一点。
  • 内部上,Shiny是否忽略隐藏的元素?
  • 在此期间,是否有人建议如何隐藏按钮而不使用hiddendisplay: none;

预先感谢你的帮助。

2个回答

3
我通过 GitHub 上的 问题 找到了解决方案。
默认情况下,Shiny 会挂起隐藏的对象。因此,如果隐藏了一个 downloadButton,相应的 downloadHandler 将被挂起。我仍然不确定 Shiny 如何使用 downloadHandler 注册下载,但是无论这个过程如何,如果对应的 downloadButton 被隐藏,它都不会被触发。
解决方案是使用 Shiny 提供的 outputOptions 函数。从 outputOptions 的帮助页面中可以看到:

suspendWhenHidden 参数,默认为 TRUE,当输出对象在网页上被隐藏时,将暂停(不执行)该输出对象。当为 FALSE 时,输出对象将不会在隐藏时挂起,并且如果它已经被隐藏和挂起,则会立即恢复。

在定义了 downloadHandler 后,通过指定 suspendWhenHidden = FALSE,我们可以避免原始问题中描述的 href 问题。
下面是原问题中包含的小Shiny应用程序的修订工作版本。
shinyApp(
  ui = fluidPage(
    tags$head(
      tags$style(HTML(".hide { display: none; }")),
      tags$script(HTML('
        Shiny.addCustomMessageHandler("trigger-button", function(message) {
          document.getElementById(message.button_id).click();
        });
      '))
    ),
    div(
      class = "disable",
      downloadButton("download_shown", "Shown"),
      div(
        class = "hide",
        downloadButton("download_hidden", "Hidden")
      )
    ),
    br(),
    actionButton("trigger_shown", "I can trigger the visible button!"),
    actionButton("trigger_hidden", "I can trigger the hidden button!")
  ),
  server = function(input, output, session) {
    output$download_shown <- downloadHandler(
      filename = "sample.txt",
      content = function(file) {
        cat("I'm visible!\n", file = file)
      }
    )
    outputOptions(output, "download_shown", suspendWhenHidden = FALSE)

    output$download_hidden <- downloadHandler(
      filename = "sample2.txt",
      content = function(file) {
        cat("I'm hidden!\n", file = file)
      }
    )
    outputOptions(output, "download_hidden", suspendWhenHidden = FALSE)

    observeEvent(input$trigger_shown, {
      session$sendCustomMessage(
        "trigger-button",
        list(button_id = "download_shown")
      )
    })

    observeEvent(input$trigger_hidden, {
      session$sendCustomMessage(
        "trigger-button",
        list(button_id = "download_hidden")
      )
    })
  }
)

记得在将相应的反应表达式分配给output之后,再对outputOptions进行调用,否则outputOptions会引发错误。

2

display:none; 会导致任何元素不被渲染,因此在文档中不占用任何空间。由此,它将不会接收到任何(真实的)pointer-events

我甚至不会指望它能够接收到通过程序触发的指针事件,因为我预计至少有几个主要浏览器会干扰它,以维护通用浏览安全原则

如果您希望您的元素成为用户交互的有效目标(无论是真实还是程序化),我建议使用...

opacity: .01;

...在它上面应用position:relative,这样它就会被渲染。如果你不想让它占据内容流中的任何空间,请考虑将position:absolute应用于它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接