首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为使用模块名称空间的R闪亮模块编写自定义JavaScript的最佳方法是什么?

为使用模块名称空间的R闪亮模块编写自定义JavaScript的最佳方法是什么?
EN

Stack Overflow用户
提问于 2018-02-22 14:11:43
回答 1查看 1.3K关注 0票数 6

我有一个复杂的闪亮的应用程序,需要使用自定义JavaScript代码。该应用程序由不同名称空间的多个地方调用的模块组成。我需要一些JavaScript代码与R代码一起“模块化”,即使用模块名称空间。我能够通过创建一个包含JS代码的定制字符串并使用shinyjs::runjs()函数执行它(下面的示例)来使它工作。例如,这是一个公平的解决方案。但是,将更复杂的超过100行的JavaScript代码放入一个使用标识符粘贴的字符串中,似乎非常容易出错,而且解决方案也不太理想(缺少高亮显示、格式痛苦等等)。是否有更好的方法来达到同样的效果?

代码语言:javascript
复制
library(shiny)
library(shinyJS)

myModuleUI <- function(id) {
    ns <- NS(id)

    tagList(
        div(id = ns("clickableElement"), class = "btn btn-primary", "Click Me"),
        div(id = ns("highlightableElement"), "This (and only this!) text should be highlighted on click")
    )
}

myModule <-  function(input, output, session) {

    ns <- session$ns

    shinyjs::runjs(paste0("
        $('#", ns("clickableElement"), "').click(function() {
            $('#", ns("highlightableElement"), "').css('background', 'yellow');
        })   
    "))
}

ui <- fluidPage(
    useShinyjs(),
    tabsetPanel(
        tabPanel(
            "Instance 1",
            myModuleUI("one")
        ),
        tabPanel(
            "Instance 2",
            myModuleUI("two")
        )
    )
)

server <- function(input, output) {
    callModule(myModule, "one")
    callModule(myModule, "two")
}

shinyApp(ui = ui, server = server)

更新

作为将来的参考,我决定分享我最终实现的解决方案。最后,我创建了每个模块一个JS文件,其中包含一个函数,将名称空间作为惟一的参数。此函数使用此命名空间创建所有需要的对象和绑定。然后,在模块开始时使用shinyjs调用该单个函数。这允许我将JS代码保存在一个单独的文件中,该文件解决了初始问题,并使代码易于管理(特别是如果您有大量JS代码)。

app.R

代码语言:javascript
复制
library(shiny)
library(shinyjs)

myModuleUI <- function(id) {
    ns <- NS(id)

    tagList(
        div(id = ns("clickableElement"), class = "btn btn-primary", "Click Me"),
        div(id = ns("highlightableElement"), "This (and only this!) text should be highlighted on click")
    )
}

myModule <-  function(input, output, session) {

    ns <- session$ns

    shinyjs::runjs(paste0("myModuleJS('", ns(""), "');"))
}

ui <- fluidPage(
    useShinyjs(),
    tags$head(
        tags$script(src = "myModuleJS.js")
    ),
    tabsetPanel(
        tabPanel(
            "Instance 1",
            myModuleUI("one")
        ),
        tabPanel(
            "Instance 2",
            myModuleUI("two")
        )
    )
)

server <- function(input, output) {
    callModule(myModule, "one")
    callModule(myModule, "two")
}

shinyApp(ui = ui, server = server)

www/myModuleJS.js

代码语言:javascript
复制
function myModuleJS(ns) {
    $('#' + ns + 'clickableElement').click(function() {
        $('#' + ns + 'highlightableElement').css('background', 'yellow');
    });
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-22 16:07:01

我认为有两种方法可以解决这一问题,尽管它们不是非常优雅的解决方案。

第一个解决方案是定义几个全局函数,例如getJavascriptSelector <- function(id, session){paste0("'#", session$ns(id), "'")}。这样,每次使用选择器时仍然需要调用此函数,并且不能在单独的文件中定义js。

因为您正在运行的javascript都是字符串,另一个解决方案是您可以定义一个函数,比如wrapJavascriptWithNamespace(script, ns),它接受脚本字符串(或js文件)和ns对象。该函数将使用regexp匹配并用会话命名空间选择器替换选择器。这样,您也可以重用您的javascript代码,但需要更多的工作,并且可能存在一些问题,例如,如果该代码需要引用全局范围元素(这可以通过使用一些关键字标记javascript使其成为模板来解决)。如果将示例中使用的代码放在字符串中:

代码语言:javascript
复制
$('#[shiny-namespace]clickableElement').click(function() {
    $('#[shiny-namespace]highlightableElement').css('background', 'yellow');
})  

您可以轻松地解析这个字符串并用ns()替换shiny-namespace。当您需要这个字符串成为普通的javascrip模板时,您只需要编写另一个函数就可以去掉[shiny-namespace]标记。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48929528

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档