Вопрос или проблема
Я работаю над приложением R Shiny, которое использует множество кнопок input_task_button(), которые отлично предотвращают спам-клики. Кнопки меняют цвет при наведении, снова при клике и снова, когда они находятся в состоянии “занято”. Проблема в том, что если вы уберете курсор с кнопки, пока она занята, то, когда она вернется в состояние “готова”, она застревает в состоянии “наведения”, пока вы не наведете курсор обратно на нее.
Я читал где-то, что это происходит потому, что кнопка на самом деле не знает, где находится курсор, она просто фиксирует, когда курсор входит или покидает ее область. Поэтому, если курсор покидает кнопку, пока она отключена, она не получает сигнала и предполагает, что курсор по-прежнему наведен.
Вот пример:
library(shiny)
library(bslib)
ui <- fluidPage(
theme = bs_theme(),
tags$head(
tags$style(HTML("
.bslib-task-button:hover {
background-color: #ffcc00 !important;
color: #000000 !important;
}
"))
),
input_task_button("task_button", "Click Me", class = "bslib-task-button"),
textOutput("result_text")
)
server <- function(input, output, session) {
observeEvent(input$task_button, {
Sys.sleep(2)
output$result_text <- renderText("Задача выполнена!")
})
}
shinyApp(ui, server)
Если вы нажимаете кнопку, ждете, пока она будет занята, и уберете курсор с кнопки, пока она занята, она останется желтого цвета, а не вернется к синему, как должна. Если вы снова наведете курсор на нее и затем уберете, она исправит себя.
Есть ли какой-то JavaScript, CSS или функция update_task_button(), которую я могу написать, чтобы исправить это поведение? В идеале, я мог бы просто добавить скрипт в одном месте и иметь его применение ко всем input_task_button() по всему приложению, так как их достаточно много, каждая из которых выполняет разные задачи. Даже что-то вроде принуждения события “покинуть мышь” каждый раз, когда input_task_button переходит из состояния занято в состояние готово, вероятно, сработает, но я не могу заставить это произойти (мои знания JavaScript отсутствуют, и CoPilot тоже не может решить эту задачу).
ОБНОВЛЕНИЕ: Хорошо, вдруг поведение моего примера стало непоследовательным. Иногда он остается желтым цветом, пока занят, и после возвращения к готовности, а иногда ведет себя именно так, как задумано, и становится светло-синим во время занятости и полностью синим, когда снова готов. Я не могу понять, что заставляет его вести себя так или иначе.
Ответ или решение
Когда вы разрабатываете приложение на R Shiny и используете элементы управления, такие как input_task_button()
, вы можете столкнуться с проблемами, связанными с изменением состояния кнопки при взаимодействии с ней. Одна из распространённых проблем, описанных вами, заключается в том, что кнопка застревает в состоянии "подсветки" (hover) после того, как курсор мыши покинет её область во время выполнения задания в состоянии "занято". Давайте рассмотрим решение этой проблемы, а также причины её возникновения.
Причины проблемы
Как вы правильно заметили, проблема заключается в том, что кнопка не получает информацию о позиции курсора мыши в момент изменения состояния. Когда кнопка переходит из состояния "занято" обратно в состояние "готово", она не знает, есть ли курсор над её областью или нет, и, следовательно, остаётся в состоянии подсветки, если курсор уходит, пока она "занята".
Решение с помощью JavaScript
Чтобы исправить это поведение, можно использовать JavaScript для принудительного обновления состояния кнопки при её переходе в состояние "готово". Мы можем добавить обработчик событий на кнопки, реагирующий на изменение их состояния.
Вот пример, как это можно сделать:
library(shiny)
library(bslib)
ui <- fluidPage(
theme = bs_theme(),
tags$head(
tags$style(HTML("
.bslib-task-button:hover {
background-color: #ffcc00 !important;
color: #000000 !important;
}
.bslib-task-button.busy {
background-color: #4a90e2; /* Цвет в состоянии 'занято' */
}
")),
tags$script(HTML("
$(document).on('shiny:inputchanged', function(event) {
if (event.name === 'task_button') {
var button = $('#task_button');
if (event.value) { // Если кнопка нажата
button.addClass('busy');
} else { // Если кнопка готова
button.removeClass('busy');
button.trigger('mouseleave'); // Принудительное срабатывание события 'mouseleave'
}
}
});
"))
),
input_task_button("task_button", "Click Me", class = "bslib-task-button"),
textOutput("result_text")
)
server <- function(input, output, session) {
observeEvent(input$task_button, {
Sys.sleep(2)
output$result_text <- renderText("Task completed!")
})
}
shinyApp(ui, server)
Объяснение кода
-
CSS Стили: Мы добавили кастомный стиль для класса кнопки, который будет применять цвет в состоянии "занято".
-
JavaScript: В оболочке стили мы используем jQuery, чтобы отслеживать изменения состояния
input_task_button
. Когда кнопка нажата, к ней добавляется классbusy
, чтобы изменить её оформление. Когда кнопка завершается, мы удаляем этот класс и принудительно вызываем событиеmouseleave
, чтобы сбросить состояние подсветки.
Заключение
Решение данной проблемы требует понимания как R Shiny и JavaScript взаимодействуют, и как состояние компонента можно изменить с помощью JavaScript. Приведённый выше код позволяет вам применять изменения ко всем кнопкам input_task_button()
, что облегчит разработку приложения и улучшит пользовательский интерфейс.
Если у вас возникнут дополнительные вопросы или потребуются уточнения, не стесняйтесь задавать их!