添加 CSS 和 JS 以覆盖页面加载模板#
参考:Adding CSS & JS and Overriding the Page-Load Template | Dash for Python Documentation | Plotly
Dash 应用程序通过 CSS 和 JavaScript 在 web 浏览器中呈现。在页面加载时,Dash 提供一个小的 HTML 模板,其中包括渲染应用程序所需的 CSS 和 JavaScript 引用。这一章涵盖了你需要知道的关于配置这个 HTML 文件以及关于在 Dash 应用程序中包括外部 CSS 和 JavaScript 的一切。
添加自定义 CSS 和 JavaScript#
在你的 Dash 应用程序中包含自定义 CSS 或 JavaScript 是很简单的。你只需在 app
目录的根目录下创建一个名为 assets
的文件夹,并在该文件夹中包含你的 CSS 和 JavaScript 文件。Dash 会自动提供这个文件夹中包含的所有文件。默认情况下,请求资产的 url
是 /assets
,但是你可以用 assets_url_path
参数将其自定义为 dash.Dash
。
小技巧
建议:你需要在 Dash 构造函数中包含 __name__
。
也就是说,app = dash.Dash(__name__)
而不是 app = dash.Dash()
。理由见 dash-app-does-not-load-assets-and-app-index-string。
示例:包含本地 CSS 和 JavaScript#
我们将创建几个文件:app.py
,一个名为 assets
的文件夹,以及该文件夹中的三个文件:
- app.py
- assets/
|-- typography.css
|-- header.css
|-- custom-script.js
在自动添加 assets
时,你需要牢记以下几点:
以下文件类型将自动包括:
CSS 文件后缀为
.css
以
.js
作为后缀的 JavaScript 文件一个名为
favicon.ico
的文件(页面标签的图标)
Dash 将包括文件在字母数字顺序的文件名。因此,如果你需要确保文件名的顺序(例如
10_typography.css
,20_header.css
),我们建议你在文件名前加上数字前缀。你可以使用正则过滤器
app = dash.Dash(assets_ignore='.*ignored.*')
来忽略assets
文件夹中的某些文件。这将阻止 Dash 加载包含上述模式的文件。如果你想包含来自远程 URL 的CSS,请参阅下一节。
你的自定义 CSS 将包含在 Dash 组件 CSS 之后。
建议在 dash init 中添加
__name__
,以确保加载assets
文件夹中的资源,例如:app = dash.Dash(__name__, meta_tags=[...])
。当您通过其他命令行运行应用程序时(如flask
命令或gunicorn/waitress
),__main__
模块将不再位于app.py
所在的位置。通过明确设置__name__
,Dash
将能够正确地找到相对assets
文件夹。
添加外部 CSS / JavaScript#
你可以通过 external_stylesheets
和 external_scripts
init 关键字将托管在你的 Dash 应用程序上的资源添加到外部。
资源可以是字符串,也可以是包含标签属性(src
、integrity
、crossorigin
等)的字典。你可以两者混合。
外部 css/js 文件在 assets
之前被加载。
例如:
import dash
import dash_html_components as html
# external JavaScript files
external_scripts = [
'https://www.google-analytics.com/analytics.js',
{'src': 'https://cdn.polyfill.io/v2/polyfill.min.js'},
{
'src': 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.core.js',
'integrity': 'sha256-Qqd/EfdABZUcAxjOkMi8eGEivtdTkh3b65xCZL4qAQA=',
'crossorigin': 'anonymous'
}
]
# external CSS stylesheets
external_stylesheets = [
'https://codepen.io/chriddyp/pen/bWLwgP.css',
{
'href': 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css',
'rel': 'stylesheet',
'integrity': 'sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO',
'crossorigin': 'anonymous'
}
]
app = dash.Dash(__name__,
external_scripts=external_scripts,
external_stylesheets=external_stylesheets)
app.layout = html.Div()
if __name__ == '__main__':
app.run_server(debug=True)
自定义 Dash 的文件或浏览器标签标题#
文档标题是出现在网页浏览器选项卡中的网页名称。
默认值是 Dash
。
在 Dash 1.14.0 中,你可以使用 title=
关键字来定制这个标题:
app = dash.Dash(__name__, title='Weekly Analytics')
根据 URL 或选项卡动态更新文档标题#
要动态设置文档标题,可以使用clientside callback
作为一个副作用更新 document.title
。下面的示例设置 document.title
的基础上,当前选择的选项卡。
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div(id='blank-output'),
dcc.Tabs(id='tabs-example', value='tab-1', children=[
dcc.Tab(label='Tab one', value='tab-1'),
dcc.Tab(label='Tab two', value='tab-2'),
]),
])
app.clientside_callback(
"""
function(tab_value) {
if (tab_value === 'tab-1') {
document.title = 'Tab 1'
} else if (tab_value === 'tab-2') {
document.title = 'Tab 2'
}
}
""",
Output('blank-output', 'children'),
Input('tabs-example', 'value')
)
if __name__ == '__main__':
app.run_server(debug=True)
基于 URL 更新页面将是类似的:回调的输入将是 dcc.Location
的 pathname
属性。关于 dcc.Location
,请参阅 url 和多页应用程序章节。
定制或删除 Dash 的"Updating..."
消息#
当一个回调运行时,Dash 更新文档标题(出现在你的浏览器标签)与"Updating..."
消息。
使用 update_title=属性
定制此消息:
app = dash.Dash(__name__, update_title='Loading...')
或者,通过设置update_title=None
来阻止此消息的出现:
app = dash.Dash(__name__, update_title=None)
自定义 Dash 的 HTML index 模板#
Dash 的 UI 是通过 Dash 的 React.js
前端动态生成的。因此,在页面加载时,Dash提 供一个非常小的 HTML 模板字符串,其中包括渲染页面所需的 CSS 和 JavaScript 以及一些简单的 HTML 元标记。
这个简单的 HTML 字符串是可定制的。如果你想自定义这个字符串:
定制页面中包含 CSS 或 JavaScript 的方式。例如,如果您想包含远程脚本,或者如果您想在 Dash 组件 CSS 之前包含 CSS
在你的应用程序中包含自定义元标记。注意,元标记也可以通过
meta_tags
参数添加(下面的例子)。通过自己实例化
DashRenderer
类,包含一个自定义版本的dash-renderer
。你可以通过下面的例子提供一个hooks
配置对象来添加请求钩子。
Option 1 - index_string#
添加一个index_string
来修改默认的 HTML 索引模板:
import dash
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.index_string = '''
<!DOCTYPE html>
<html>
<head>
{%metas%}
<title>{%title%}</title>
{%favicon%}
{%css%}
</head>
<body>
<div>My Custom header</div>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
{%renderer%}
</footer>
<div>My Custom footer</div>
</body>
</html>
'''
app.layout = html.Div('Simple Dash App')
if __name__ == '__main__':
app.run_server(debug=True)
{%key%}
是模板变量,Dash 会用默认属性自动填充。可用的key
是:
{%metas%}
(optional):注册的meta
标签包含在dash.Dash
中的meta_tags
参数中。{%favicon%}
(optional):如果在assets
文件夹中找到favicon
链接标签。{%css%}
(optional):<link> CSS 资源的标签。这些资源包括 Dash 组件库CSS资源以及在assets
文件夹中找到的任何 CSS 资源。{%title%}
(optional):页面内容 <title>标签。了解更多关于<title/>{%config%}
(required):一个自动生成的标签,包括从 Dash 的后端到前端的配置设置(dash-renderer
)。{%app_entry%}
(required):渲染 Dash 布局的容器。{%scripts%}
(required):渲染 Dash 应用所需的 JavaScript 脚本集。这包括 Dash 组件的 JavaScript 文件以及在assets
文件夹中找到的任何 JavaScript 文件。{%renderer%}
(required):通过调用new DashRenderer()
实例化dash-renderer
的JavaScript
脚本
Option 2 - interpolate_index#
如果你的 HTML 内容不是静态的,或者你想 introspect 或修改模板变量,那么你可以覆盖 Dash.interpolate_index
方法。
import dash
import dash_html_components as html
class CustomDash(dash.Dash):
def interpolate_index(self, **kwargs):
# Inspect the arguments by printing them
print(kwargs)
return '''
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>
<body>
<div id="custom-header">My custom header</div>
{app_entry}
{config}
{scripts}
{renderer}
<div id="custom-footer">My custom footer</div>
</body>
</html>
'''.format(
app_entry=kwargs['app_entry'],
config=kwargs['config'],
scripts=kwargs['scripts'],
renderer=kwargs['renderer'])
app = CustomDash()
app.layout = html.Div('Simple Dash App')
if __name__ == '__main__':
app.run_server(debug=True)
不像index_string
方法,我们使用模板字符串变量,传递到interpolate_index
的关键字变量已经被求值了。
在上面的例子中,当我们打印interpolate_index
的输入参数时,应该会看到这样的输出:
{
'title': 'Dash',
'app_entry': '\n<div id="react-entry-point">\n <div class="_dash-loading">\n Loading...\n </div>\n</div>\n',
'favicon': '',
'metas': '<meta charset="UTF-8"/>',
'scripts': '<script src="https://unpkg.com/react@15.4.2/dist/react.min.js"></script>\n<script src="https://unpkg.com/react-dom@15.4.2/dist/react-dom.min.js"></script>\n<script src="https://unpkg.com/dash-html-components@0.14.0/dash_html_components/bundle.js"></script>\n<script src="https://unpkg.com/dash-renderer@0.20.0/dash_renderer/bundle.js"></script>',
'renderer': '<script id="_dash-renderer" type="application/javascript">var renderer = new DashRenderer();</script>',
'config': '<script id="_dash-config" type="application/json">{"requests_pathname_prefix": "/", "url_base_pathname": "/"}</script>',
'css': ''
}
scripts
和css
键的值可能会不同,这取决于您包含的组件库或assets
文件夹中的文件。
使用请求钩子定制 dash-renderer#
为了实例化你自己的dash-renderer
版本,你可以覆盖 Dash 的HTML Index Template,并提供你自己的脚本来代替标准脚本。这个脚本应该在某处调用var renderer = new DashRenderer();
,它实例化了DashRenderer
类。当你设置app.index_string
时,你可以将这个脚本添加到你的 index HTML 中,或者你可以像这样简单地覆盖app.renderer
:
import dash
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.renderer = 'var renderer = new DashRenderer();'
app.layout = html.Div('Simple Dash App')
if __name__ == '__main__':
app.run_server(debug=True)
当你提供你自己的DashRenderer
时,你也可以传入一个钩子对象来保存request_pre
和request_post
函数。这些请求钩子将在Dash
向其后端发出请求之前和之后被触发。这里有一个例子:
import dash
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.renderer = '''
var renderer = new DashRenderer({
request_pre: (payload) => {
// print out payload parameter
console.log(payload);
},
request_post: (payload, response) => {
// print out payload and response parameter
console.log(payload);
console.log(response);
}
})
'''
app.layout = html.Div('Simple Dash App')
if __name__ == '__main__':
app.run_server(debug=True)
请注意,request_pre
函数将正在发送的请求的有效负载作为其参数,而request_post
函数将有效负载和服务器的响应同时作为参数。这些可以在我们的功能中改变,允许你修改Dash
发送给服务器的响应和请求对象。在上面的例子中,request_pre
函数在每次服务器调用之前被触发,在这个例子中,它将console.log()
请求参数。request_post
函数将在每次服务器调用后触发,在我们的示例中还将打印出响应参数。
定制 Meta 标记#
要在你的应用程序中添加自定义元标签,你可以覆盖Dash
的 HTML 索引模板。另外,Dash
提供了一个快捷方式:你可以直接在 Dash
构造函数中指定 meta
标签:
import dash
import dash_html_components as html
app = dash.Dash(meta_tags=[
# A description of the app, used by e.g.
# search engines when displaying search results.
{
'name': 'description',
'content': 'My description'
},
# A tag that tells Internet Explorer (IE)
# to use the latest renderer version available
# to that browser (e.g. Edge)
{
'http-equiv': 'X-UA-Compatible',
'content': 'IE=edge'
},
# A tag that tells the browser not to scale
# desktop widths to fit mobile screens.
# Sets the width of the viewport (browser)
# to the width of the device, and the zoom level
# (initial scale) to 1.
#
# Necessary for "true" mobile support.
{
'name': 'viewport',
'content': 'width=device-width, initial-scale=1.0'
}
])
app.layout = html.Div('Simple Dash App')
if __name__ == '__main__':
app.run_server(debug=True)