r - 如果我将 Shiny 中的dashboardPage 写为 renderUI,则 html 文件与 jQuery 无法正常工作

我有一个 shiny 应用程序,其中我在 shiny 仪表板中嵌入了一个 iframe。我希望 iframe 能够扩展高度,为此我实现了一个带有 jquery 脚本的 html 文件。

test.html 文件看起来像这样并且运行良好:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
    <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css">

    <style>
        #div1 {
            position: relative;
            width: 100%;
            height: 200px;
            
        }
    </style>

</head>
<body>

       <div id="div1"> <iframe id="ifr" src="https://pubmed.juliasanchezmartinez98.workers.dev/" onLoad="doOnLoad()" style="width:100%; height:100%;"></iframe> 
       
<script>

        $("#div1").resizable({
            start: function (event, ui) {
                ui.element.append($("<div/>", {
                    id: "iframe-barrier",
                    css: {
                        position: "absolute",
                        top: 0,
                        right: 0,
                        bottom: 0,
                        left: 0,
                        "z-index": 10
                    }
                }));
            },
            stop: function (event, ui) {
                $("#iframe-barrier", ui.element).remove();
               
            },
            resize: function (event, ui) {
                $("iframe", ui.element).width(ui.size.width).height(ui.size.height);
               
            }
        });
        $('#div1').resize(function () {
        }); 


    </script>
  
</body>
</html>

当我在仪表板 ui 中插入此 html 文件时,问题就出现了。

如果我这样做,它会起作用:

library(shiny)
library(shinyjs)
library(shinydashboard)


num_engine ="test.html"
ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(
    fluidRow(
      h1("Evaluating a Search Engine"),
      box(width = 12,
      useShinyjs(),
      includeHTML(num_engine)),
      box(width=12,textAreaInput("txt", "Enter the answer below:",height = "100px", width = "100%"),
      actionButton("submit_answer", "Submit", class = "btn-primary")),
    ),
  ))



server <- function(input, output) {
}

runApp(list(ui = ui, server = server), launch.browser = TRUE)

但是当我尝试使用 renderUI 将其实现为 output$body 时,iframe 的高度扩展不起作用。

library(shiny)
library(shinyjs)
library(shinydashboard)

header <- dashboardHeader( title = "Welcome", uiOutput("logoutbtn"))

sidebar <- dashboardSidebar(uiOutput("sidebarpanel"))
body <- dashboardBody(shinyjs::useShinyjs(), uiOutput("body"))
ui <- dashboardPage(header, sidebar, body, skin = "blue")



server <- function(input, output) {
  num_engine ="test.html"
  output$body <- renderUI({
    fluidRow(
      h1("Evaluating a Search Engine"),
      box(width = 12,
          useShinyjs(),
          includeHTML(num_engine)),
      box(width=12,textAreaInput("txt", "Enter the answer below:",height = "100px", width = "100%"),
          actionButton("submit_answer", "Submit", class = "btn-primary")),
    )
  })
  
}

runApp(list(ui = ui, server = server), launch.browser = TRUE)

它们基本上是相同的代码。有谁知道为什么会这样?

回答1

首先,您需要了解 HTML 是如何呈现的以及 renderUI 是如何工作的。

  1. HTML 中的 head 标记在加载正文部分之前首先加载。在您的第一种方法中,当应用程序启动时,您的 test.html 中的 head 标记被添加/加入主应用程序的其他头部元素,成为一个大的 head 标记。因此,当您执行第一种方法时, Shiny 实际上将您的 HTML 拆分为多个部分,头对头,身体对身体。当 head 在 body 之前加载(并完成加载)时,可以找到 resizable,因为 head 脚本已完成加载。
  2. 使用 renderUI 时,headbody 中的所有脚本都在同一级别下进行评估。当您使用 renderUI 时,无需等待 head 完成运行并执行其他操作。因此,当您调用 $("#div1").resizable 时,它尚未定义。它仍在运行。对我来说,这更像是 renderUI 功能的限制。 Shiny 应该有一些东西等待 renderUI 中的 head 标记。

这里有一个解决方法:我们可以手动添加一个WaitUntil的等待函数,它会一直等待,直到某些条件满足,然后我们做一些事情。

library(shiny)
library(shinyjs)
library(shinydashboard)

header <- dashboardHeader( title = "Welcome", uiOutput("logoutbtn"))

sidebar <- dashboardSidebar(uiOutput("sidebarpanel"))
body <- dashboardBody(
    tags$script(HTML(
        "
            var WaitUntil = (function(){
                var waitUntil=function(condfunc, callback, interval, trys){
                    var getGuid = getGuid||function() {
                        var d = new Date().getTime();
                        var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                            var r = (d + Math.random()*16)%16 | 0;
                            d = Math.floor(d/16);
                            return (c=='x' ? r : (r&0x3|0x8)).toString(16);
                        });
                        return uuid;
                    };
                    var timer = {}, counter={};
                    var waiter = function(condfunc, callback, interval, trys, guid){
                        guid = guid || getGuid();
                        interval = interval || 100;
                        trys = trys || 300;
                        counter[guid] = counter[guid] ? counter[guid]++ : 1;
                        if(counter[guid]>trys){
                            if(timer[guid]) clearTimeout(timer[guid]);
                            //callback('fail');
                            return;
                        }
                        timer[guid] = setTimeout(function(){
                            if(condfunc()){
                               if(timer[guid]) clearTimeout(timer[guid]);
                                callback('ok');
                            } else {
                                if(timer[guid]) clearTimeout(timer[guid]);
                                waiter(condfunc, callback, interval, trys, guid);
                            }
                        }, interval);
                    }
                    waiter(condfunc, callback, interval, trys);
                }
                return waitUntil;
            })();            
            "
    )),
    shinyjs::useShinyjs(), uiOutput("body")
)
ui <- dashboardPage(header, sidebar, body, skin = "blue")



server <- function(input, output) {
    num_engine ="test.html"
    output$body <- renderUI({
        fluidRow(
            h1("Evaluating a Search Engine"),
            box(width = 12,
                useShinyjs(),
                includeHTML(num_engine)),
            box(width=12,textAreaInput("txt", "Enter the answer below:",height = "100px", width = "100%"),
                actionButton("submit_answer", "Submit", class = "btn-primary")),
        )
    })
    
}

runApp(list(ui = ui, server = server), launch.browser = TRUE)

WaitUntil JS 函数(归功于 https://greasyfork.org/en/scripts/412875-waituntil/code)被添加到主应用程序中。注意不要在你的 renderUI 里面,因为你可能想多次使用它,所以你只需要定义一次。

对于 test.html,将 resizable 包裹在 WaitUntil

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
    <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css">
    <style>
        #div1 {
            position: relative;
            width: 100%;
            height: 200px;
    
        }
    </style>
</head>
<body>
    <div id="div1"> <iframe id="ifr" src="https://pubmed.juliasanchezmartinez98.workers.dev/" onLoad="doOnLoad()" style="width:100%; height:100%;"></iframe>
    <script>
    WaitUntil(function(){return typeof $("#div1").resizable !=="undefined"}, function(){
           $("#div1").resizable({
            start: function (event, ui) {
                ui.element.append($("<div/>", {
                    id: "iframe-barrier",
                    css: {
                        position: "absolute",
                        top: 0,
                        right: 0,
                        bottom: 0,
                        left: 0,
                        "z-index": 10
                    }
                }));
            },
            stop: function (event, ui) {
                $("#iframe-barrier", ui.element).remove();
    
            },
            resize: function (event, ui) {
                $("iframe", ui.element).width(ui.size.width).height(ui.size.height);
    
            }
        });
        $('#div1').resize(function () {
        });
    });
    </script>
</body>
</html>

相似文章

随机推荐

最新文章