将display属性设置为none将删除href目标

时间:2017-02-24 22:43:37

标签: html css r shiny

我在R中构建一个Shiny应用程序时遇到了这个问题。在应用程序中,一个动作按钮用于触发一个隐藏的下载按钮。这将允许我观察操作按钮事件,对该事件做出反应,然后触发下载过程。

但是,当我将下载按钮的显示属性设置为隐藏按钮的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 个答案:

答案 0 :(得分:2)

display:none;会导致任何元素无法呈现。因此,它不会占用文档中的任何空间。因此,它不会收到任何(真实的)pointer-events

我甚至不会指望它能够以一般浏览安全原则的名义接收以编程方式触发的指针事件,因为我预计至少有几个主流浏览器会干扰它。

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

opacity: .01;

......就此而言。这样它将被渲染。如果您不希望它占用内容流中的任何空格,请考虑将position:absolute应用于其中。

答案 1 :(得分:1)

我已经在GitHub上发现了这个issue的解决方案。

默认情况下,Shiny会暂停隐藏的对象。因此,通过隐藏downloadButton,相应的downloadHandler被暂停。我仍然不确定Shiny如何使用downloadHandler来注册下载,但是但是过程有效,如果正如我所说的那样隐藏相应的downloadButton,则不会触发。

解决方案是使用Shiny提供的outputOptions功能。在outputOptions的帮助页面中,

  

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

通过在定义suspendWhenHidden = FALSE后指定downloadHandler,我们可以阻止原始问题中描述的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")
      )
    })
  }
)

在将相应的反应性表达式分配给outputOptions后,请务必拨打output,否则outputOptions会引发错误。