如何在完整Shiny应用中嵌入learnr交互式教程?
如何在Shiny应用中嵌入完整的交互式learnr教程
你遇到的问题其实很常见:learnr的shiny_prerendered运行时本质上是一个独立的Shiny应用,所以直接用includeMarkdown只会渲染静态文本,run_tutorial又会触发嵌套runApp()的错误。下面给你两种可行的解决方案,都能完整保留learnr教程的交互功能(包括可运行代码块、测验):
方案一:用iframe嵌入已渲染的教程(最快捷)
这是最简单直接的方法,步骤如下:
先渲染你的教程为HTML文件
在R控制台运行这条命令,把tutorial.Rmd编译成可交互的HTML:rmarkdown::render("tutorial.Rmd")执行后会在同一个目录下生成
tutorial.html文件。在Shiny的UI中嵌入这个HTML
修改你的ui.R,用tags$iframe把教程嵌入到应用里:# ui.R shinyUI(fluidPage( titlePanel("我的Shiny应用 + Learnr教程"), tags$iframe( src = "tutorial.html", width = "100%", # 占满容器宽度 height = "800px", # 可根据教程内容调整高度 frameBorder = 0 # 去掉iframe的边框,更美观 ) ))只要
tutorial.html和你的Shiny文件在同一个目录下,就能正常加载,所有交互功能都会保留。
方案二:将教程作为Shiny模块嵌入(更深度集成)
如果你希望教程和Shiny应用共享会话数据(比如用户输入、全局变量),可以用learnr的模块功能(需要learnr版本≥0.10.0):
创建教程模块文件
新建一个tutorial_module.R文件,定义模块的UI和服务器逻辑:# tutorial_module.R library(learnr) # 模块UI函数 tutorial_ui <- function(id) { ns <- NS(id) shiny_prerendered_ui( ns("tutorial"), file = "tutorial.Rmd" ) } # 模块服务器函数 tutorial_server <- function(id) { moduleServer(id, function(input, output, session) { shiny_prerendered_server( "tutorial", file = "tutorial.Rmd" ) }) }在Shiny应用中调用模块
修改你的ui.R和server.R来加载这个模块:# ui.R source("tutorial_module.R") shinyUI(fluidPage( titlePanel("集成化Shiny应用"), tutorial_ui("my_tutorial") )) # server.R source("tutorial_module.R") shinyServer(function(input, output, session) { tutorial_server("my_tutorial") })这种方法不需要预先渲染HTML,learnr会在应用启动时动态处理你的Rmd文件,还能实现教程和主应用的数据交互。
一些小提示
- 确保你的
learnr和shiny包都是最新版本,避免兼容性问题。 - 用iframe时,如果教程内容很长,可以用JavaScript实现自适应高度(比如监听iframe内容变化调整高度)。
- 如果遇到资源加载失败的问题,检查一下文件路径是否正确,或者把Shiny应用的工作目录设置为包含所有文件的目录。
内容的提问来源于stack exchange,提问作者Carolyn
相关产品推荐
相关产品推荐

