【问题标题】:Adding JavaScript to my Plotly Dash app (Python)将 JavaScript 添加到我的 Plotly Dash 应用程序 (Python)
【发布时间】:2021-07-11 15:36:48
【问题描述】:

我正在使用 Python 中的 Dash 构建仪表板。我已经很好地配置了所有图表(它在server here 上运行),下一步是创建一个响应式导航栏和一个页脚。目前看起来像这样:

当我缩小宽度时,它看起来像这样:

我想为该按钮添加功能,以便在点击时隐藏三个链接。我正在尝试使用 JavaScript 和这段代码来切换 CSS 'active' 属性:

 var toggleButton = document.getElementsByClassName('toggle-button')[0]
 var navBarLinks = document.getElementsByClassName('navbar-links')[0]

 function toggleFunction() {
     navBarLinks.classList.toggle('active')
 }

 toggleButton.addEventListener('click', toggleFunction)

基本上,当navbar-links 类处于活动状态时,我希望将其设置为display: flex,而当它不活动时,我希望将其设置为display: none

在 Python 屏幕中定义的 HTML 元素在这里:

    html.Nav([

    html.Div('Covid-19 global data Dashboard', className='dashboard-title'),

    html.A([html.Span(className='bar'),
            html.Span(className='bar'),
            html.Span(className='bar')],
           href='#', className='toggle-button'),

    html.Div(
        html.Ul([
            html.Li(html.A('Linked-In', href='#')),
            html.Li(html.A('Source Code', href='#')),
            html.Li(html.A('CSV Data', href='#'))
        ]),
        className='navbar-links'),

], className='navbar')

我没想到通过 JavaScript 访问元素会出现问题。经过一番研究,我发现 JavaScript 在执行 getElementsByClassName 函数时返回值为 null。那是因为该功能是在呈现页面之前运行的(据我所知)。它给了我这个错误:

这个项目越来越大,所以我不知道我应该在这篇文章中包含哪些部分,但我会分享git repositorypreview of the page。有没有简单的解决方法?

【问题讨论】:

  • 我认为您需要创建一个在文档或窗口加载时间初始化的函数。 JS 可能在元素 toggle-button 加载之前已经运行,因此出现“未定义错误”...
  • 这能回答你的问题吗? How to make JavaScript execute after page load?
  • 我认为可以,但由于我的 JS 知识限制,我不知道如何在我的 JS 脚本中实现它
  • 您可以为load 事件添加事件监听器。有关示例,请参见链接帖子 (link) 的第二个答案的第二个示例。您可以将问题中的代码放在 load 事件的处理程序函数中,这可能会起作用。
  • 我不认为你需要这个 btw 的 javascript。你也可以通过 Dash 中的回调来实现。

标签: javascript python css plotly plotly-dash


【解决方案1】:

Dash 回调解决方案(无 Javascript):

import dash
import dash_html_components as html
from dash.dependencies import Output, Input, State

navbar_base_class = "navbar-links"

app = dash.Dash(__name__)

app.layout = html.Nav(
    [
        html.Div("Covid-19 global data Dashboard", className="dashboard-title"),
        html.A(
            id="toggle-button",
            children=[
                html.Span(className="bar"),
                html.Span(className="bar"),
                html.Span(className="bar"),
            ],
            href="#",
            className="toggle-button",
        ),
        html.Div(
            id="navbar-links",
            children=html.Ul(
                children=[
                    html.Li(html.A("Linked-In", href="#")),
                    html.Li(html.A("Source Code", href="#")),
                    html.Li(html.A("CSV Data", href="#")),
                ],
            ),
            className=navbar_base_class,
        ),
    ],
    className="navbar",
)


@app.callback(
    Output("navbar-links", "className"),
    Input("toggle-button", "n_clicks"),
    State("navbar-links", "className"),
    prevent_initial_call=True,
)
def callback(n_clicks, current_classes):
    if "active" in current_classes:
        return navbar_base_class
    return navbar_base_class + " active"


if __name__ == "__main__":
    app.run_server(debug=True)

上面代码的思路是把toggle-button点击当成Input,把navbar-links的当前值当成State。我们可以使用此状态来确定是否应该添加active 类或删除它。在回调中返回新的className 值。


Javascript 解决方案:

window.addEventListener("load", function () {
  var toggleButton = document.getElementsByClassName("toggle-button")[0];
  var navBarLinks = document.getElementsByClassName("navbar-links")[0];

  function toggleFunction() {
    navBarLinks.classList.toggle("active");
  }

  toggleButton.addEventListener("click", toggleFunction);
});

加载整个页面时会触发 load 事件,包括所有相关资源,例如样式表和图像。这与 DOMContentLoaded 不同,后者在页面 DOM 加载后立即触发,无需等待资源完成加载。

https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event

DOMContentLoaded 更适合使用,但它仅适用于 load

【讨论】:

  • 我刚刚实现了python解决方案,帮了大忙,非常感谢!我首先尝试了 JS 解决方案,但它没有用。这仍然解决了我的问题,所以你不用担心
【解决方案2】:

您可以推迟 JavaScript 代码的执行,直到通过来自 dash-extensionsDeferScript 组件加载 React 之后。这是一个小例子,

import dash
import dash_html_components as html
from html import unescape
from dash_extensions import DeferScript


mxgraph = r'{"highlight":"#0000ff","nav":true,"resize":true,"toolbar":"zoom layers lightbox","edit":"_blank","xml":"<mxfile host=\"app.diagrams.net\" modified=\"2021-06-07T06:06:13.695Z\" agent=\"5.0 (Windows)\" etag=\"4lPJKNab0_B4ArwMh0-7\" version=\"14.7.6\"><diagram id=\"YgMnHLNxFGq_Sfquzsd6\" name=\"Page-1\">jZJNT4QwEIZ/DUcToOriVVw1JruJcjDxYho60iaFIaUs4K+3yJSPbDbZSzN95qPTdyZgadm/GF7LAwrQQRyKPmBPQRzvktidIxgmwB4IFEaJCUULyNQvEAyJtkpAswm0iNqqegtzrCrI7YZxY7Dbhv2g3r5a8wLOQJZzfU4/lbByoslduPBXUIX0L0cheUrugwk0kgvsVojtA5YaRDtZZZ+CHrXzukx5zxe8c2MGKntNgknk8bs8fsj3+KtuDhxP+HZDVU5ct/RhatYOXgGDbSVgLBIG7LGTykJW83z0dm7kjklbaneLnEnlwFjoL/YZzb93WwNYgjWDC6EEdkuC0cZEO7p3i/6RF1WutL8nxmnkxVx6UcUZJIy/LgP49622mO3/AA==</diagram></mxfile>"}'
app = dash.Dash(__name__)
app.layout = html.Div([
    html.Div(className='mxgraph', style={"maxWidth": "100%"}, **{'data-mxgraph': unescape(mxgraph)}),
    DeferScript(src='https://viewer.diagrams.net/js/viewer-static.min.js')
])

if __name__ == '__main__':
    app.run_server()

【讨论】:

  • 好的,我会记住这个解决方案,但我会保留我的 python 解决方案,因为我对它的理解更好。非常感谢!
猜你喜欢
  • 2019-01-21
  • 1970-01-01
  • 2021-11-09
  • 1970-01-01
  • 2020-09-04
  • 2021-12-04
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
相关资源
最近更新 更多