切换滑块输入颜色而不闪烁

Switching slider input colors without flickering

我正在尝试让闪亮的应用程序在特定条件下切换滑块输入的颜色以及更新。下面的示例演示了我正在尝试做的事情的不完美版本。它只有一个滑块输入和两个按钮。这两个按钮使用 updateSliderInput 函数来更改滑块的某些属性,然后我使用 shinyjs 向滑块添加一个 class 使其颜色发生变化。

ui.R

library(shiny)
library(shinyjs)

shinyUI(fluidPage(
    includeCSS('www/style.css'),
    useShinyjs(),
    sliderInput("slider",
                "A slider",
                min = 1,
                max = 50,
                value = 30),
    actionButton('type1','type 1'),
    actionButton('type2','type 2')

))

server.R

library(shiny)
library(shinyjs)

shinyServer(function(input, output,session) {

    observeEvent(input$type1,{
        updateSliderInput(session,
                          inputId = 'slider',
                          min = 0,
                          value = 10,
                          max = 20)
        delay(3,{
            removeClass(selector = '.js-irs-0', class = 'type2')
            addClass(selector = '.js-irs-0', class = 'type1')
        })
    })

    observeEvent(input$type2,{
        updateSliderInput(session,
                          inputId = 'slider',
                          min = 0,
                          value = 20,
                          max = 40)
        delay(3,{
            removeClass(selector = '.js-irs-0', class = 'type1')
            addClass(selector = '.js-irs-0', class = 'type2')
        })
    })

})

(www/css 文件在问题的末尾,因为它的内容不太相关)

在快速系统中,结果看起来不错,因为行之间的执行延迟很小。但是,如果我切换到较慢的机器,当在 type1type2 提供的颜色之间切换时,您会看到滑块闪烁回原来的蓝色。发生这种情况是因为 updateSliderInput 在应用自己的更新时删除了任何手动添加到滑块的 classes。我正在寻找一种方法来防止这种情况发生。我怀疑可以使用 session$sendCustomMessagesession$sendInputMessage 来完成,但到目前为止我还没有成功。

注意:delay 函数是必需的,因为没有它,updateSliderInput 会覆盖 addClass 执行的更改。 removeClass 不是绝对必要的,因为 updateSliderInput 已经删除了手动添加的 classes 但我保留了这条线,因为修复可能涉及阻止 updateSliderInput 这样做。

如约而至:

www/style.css

.type1 .irs-bar {
border-top-color: #8B1A1A;
border-bottom-color: #8B1A1A;
}

.type1 .irs-bar-edge {
border-color: #8B1A1A;
}

.type1 .irs-single, .type1 .irs-bar-edge, .type1 .irs-bar {
background: #8B1A1A;
}

.type2 .irs-bar {
border-top-color: #6959CD;
border-bottom-color: #6959CD;
}

.type2 .irs-bar-edge {
border-color: #6959CD;
}

.type2 .irs-single, .type2 .irs-bar-edge, .type2 .irs-bar {
background: #6959CD;
}

与其处理添加 类 并试图阻止 updateSliderInput 覆盖它们,不如随意切换滑块的默认颜色,这样就不会发生闪烁,如下面的代码所示.

请注意,这种方法仍然存在问题。例如,如果您正在编写一个依赖于此的模块,我不知道有什么简单的方法可以检测您自己的滑块的 ID,以便您可以正确编辑默认颜色。

ui.R

library(shiny)

shinyUI(fluidPage(
    includeCSS('www/type1.css'), # your initial look
    htmlOutput('defaultSlider'), # update to change colors
    sliderInput("slider",
                "A slider",
                min = 1,
                max = 50,
                value = 30),
    actionButton('type1','type 1'),
    actionButton('type2','type 2')

))

server.R

library(shiny)

shinyServer(function(input, output,session) {


    observeEvent(input$type1,{
        updateSliderInput(session,
                          inputId = 'slider',
                          min = 0,
                          value = 10,
                          max = 20)

        output$defaultSlider = renderUI({
            includeCSS('www/type1.css')
        })
    })

    observeEvent(input$type2,{
        updateSliderInput(session,
                          inputId = 'slider',
                          min = 0,
                          value = 20,
                          max = 40)

        output$defaultSlider = renderUI({
            includeCSS('www/type2.css')
        })
    })
})

www/type1.css

.js-irs-0 .irs-bar {
    border-top-color: #8B1A1A;
        border-bottom-color: #8B1A1A;
}

.js-irs-0 .irs-bar-edge {
    border-color: #8B1A1A;
}

.js-irs-0 .irs-single, .js-irs-0 .irs-bar-edge, .js-irs-0 .irs-bar {
    background: #8B1A1A;
}

www/type2.css

.js-irs-0 .irs-bar {
    border-top-color: #6959CD;
        border-bottom-color: #6959CD;
}

.js-irs-0 .irs-bar-edge {
    border-color: #6959CD;
}

.js-irs-0 .irs-single, .js-irs-0 .irs-bar-edge, .js-irs-0 .irs-bar {
    background: #6959CD;
}

如果您查看 shiny 中用于更新滑块输入的 javsacript 代码(input_binding_slider.js 文件),shiny 会调用滑块自己的库的 API 函数来进行更新。我刚刚在 javascript 控制台中自己尝试了 运行 这个更新行,它确实清除了任何自定义 classes(我怀疑它不是字面上清除 class,而是可能只是重建 HTML 而并不关心尝试保留任何随机添加的意外 classes)。

我没有适合您的完美解决方案,但有一些您可能喜欢或不喜欢的备选方案:

解决方案 1:将 class 添加到输入的父级 div,并相应地稍微更改 CSS 选择器(我推荐的解决方案)

解决方案 2:使用 uiOutput+renderUI 而不是 updateSliderInput,在 renderUI 中,您可以生成一个滑块输入,它在构建时已经具有给定的 class(使用 htmltools::tagAppendAttributes()) (更多工作但可以工作)

解决方案 3:使用您自己的 javascript 进行更新并立即添加 class(不推荐)

注意:我无法重现闪烁的问题,所以我没有实际检查具体问题是否已解决,但我怀疑它可能有所帮助。

注2:我认为delay(0, ...)可以,我认为你不需要在那里输入正数