Dash应用浏览器端回调常用方法总结
本文示例代码已上传至我的
Github仓库https://github.com/CNFeffery/dash-master
大家好我是费老师,回调函数是我们在Dash应用中实现各种交互功能的核心,在绝大多数情况下,我们只需要以纯Python的方式编写常规服务端回调函数即可,这也贯彻了Dash无需编写javascript即可构建web应用的理念。
但这并不代表在Dash应用中我们只能使用Python,更自由地,Dash针对回调函数编写还提供了client side callback(我们通常称作浏览器端回调)相关功能,使得我们可以在仍然使用Python编排回调函数角色的基础上,嵌入自定义的javascript代码片段来执行相应的回调输入输出逻辑,从而解决一些特殊的需求。今天的文章中,我就将带大家一起学习Dash浏览器端回调常用的方法和技巧。

阅读本文大约需要15分钟
浏览器端回调,顾名思义,其对应的函数体计算过程是在每个用户的本地浏览器中执行的,这在一些特殊的场景下,可以帮助我们节省服务器算力、网络传输带宽等消耗,还可以在用户网络状况很差时,提升一些用户交互功能的流畅度,亦或是可以让我们在Dash应用中额外引入javascript生态的功能(譬如在Dash应用中高效渲染原生echarts图表)。

而在Dash中,我们主要有两种定义浏览器端回调的方式:
1 基于app.clientside_callback编写简单浏览器端逻辑
此种浏览器端回调定义方式适用于执行非常简单的javascript代码片段,只需要为app.clientside_callback()的第一个参数传入字符串形式的javascript函数体即可(推荐使用箭头函数),其中函数体内部参数的输入,以及结果的输出,原则类似常规的回调函数。
举个例子,我们来实现一段非常简单的逻辑,通过按钮的点击,来触发对应模态框的打开:

对应app.clientside_callback的完整应用代码如下:
app1.py
import dash
from dash import html
import feffery_antd_components as fac
from dash.dependencies import Input, Output
app = dash.Dash(__name__)
app.layout = html.Div(
[
fac.AntdButton(
'打开模态框',
id='open-modal',
type='primary'
),
fac.AntdModal(
fac.AntdParagraph('测试内容'*100),
id='modal',
title='模态框示例'
)
],
style={
'padding': '50px 100px'
}
)
app.clientside_callback(
'(nClicks) => true',
Output('modal', 'visible'),
Input('open-modal', 'nClicks'),
prevent_initial_call=True
)
if __name__ == '__main__':
app.run(debug=True)
可以看到,写法非常简单,对于编写此类简单浏览器端回调的需求,我们只需要用到javascript最基础的语法,非常的方便,再来个稍微复杂一点的例子,我们基于轮询组件,实现当前系统时间的实时更新:
app2.py

import dash
from dash import html, dcc
import feffery_antd_components as fac
from dash.dependencies import Input, Output
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Interval(
id='interval',
interval=1000 # 每秒触发一次
),
fac.AntdStatistic(
id='current-datetime',
title='当前时间'
)
],
style={
'padding': '50px 100px'
}
)
app.clientside_callback(
'''(n_intervals) => {
return `${new Date().toLocaleDateString().replaceAll("/", "-")} ${new Date().toLocaleTimeString()}`
}''',
Output('current-datetime', 'value'),
Input('interval', 'n_intervals')
)
if __name__ == '__main__':
app.run(debug=True)
2 基于ClientsideFunction编写复杂浏览器端回调
如果我们想要执行的浏览器端回调逻辑比较复杂和冗长,那么在app.clientside_callback里用字符串的方式写大段的javascript代码就不太高效了♂️,相应的我们可以改为使用ClientsideFunction来定义。
使用ClientsideFunction来定义浏览器端回调,我们首先需要在我们的Dash应用静态资源目录下(默认为assets)建立相应的js文件(名称随意,Dash应用会自动加载静态资源目录下的js文件到用户浏览器中),并在该js文件中按照下列格式定义若干javascript回调函数:
window.dash_clientside = Object.assign({}, window.dash_clientside, {
clientside: {
func1: () => {
// write your code logic
}
}
});
接着在相应的Python程序中配合ClientsideFunction按照下列格式关联编排回调函数即可:
app.clientside_callback(
ClientsideFunction(
namespace='clientside',
function_name='函数名称'
),
# 照常编排回调角色
)
废话不多说,我们直接将上文中实时刷新系统时间的示例改造成ClientsideFunction形式以便理解:
assets/clientside_callbacks.js
window.dash_clientside = Object.assign({}, window.dash_clientside, {
clientside: {
update_datetime: (n_intervals) => {
return `${new Date().toLocaleDateString().replaceAll("/", "-")} ${new Date().toLocaleTimeString()}`
}
}
});
app3.py
import dash
from dash import html, dcc
import feffery_antd_components as fac
from dash.dependencies import Input, Output, ClientsideFunction
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Interval(
id='interval',
interval=1000 # 每秒触发一次
),
fac.AntdStatistic(
id='current-datetime',
title='当前时间'
)
],
style={
'padding': '50px 100px'
}
)
app.clientside_callback(
ClientsideFunction(
namespace='clientside',
function_name='update_datetime'
),
Output('current-datetime', 'value'),
Input('interval', 'n_intervals')
)
if __name__ == '__main__':
app.run(debug=True)
这样做的好处在于,我们可以把相对复杂的javascript逻辑在原生的js程序里编写,从而配合现代化ide获得更高效的编程体验,并且利用ClientsideFunction形式,可以很方便地实现外部js框架的引入使用,譬如引入使用原生echarts,篇幅有限,今天先按下不表,之后另外发文举例介绍。
3 编写浏览器端回调的常用技巧
通过上文,我们知晓了Dash中构建浏览器端回调的基本形式,下面我们补充一些有关浏览器端回调的实用技巧:
3.1 配合插件快捷生成模板代码
编写浏览器端回调,尤其是配合ClientsideFunction时,其代码格式还是有些特殊的,不过别担心,如果你恰好在使用vscode编写Dash应用,可以在拓展里安装由我开发维护的插件feffery-dash-snippets,安装完成后,可以通过输入一些快捷短语,进行相关代码模板的生成。
目前针对浏览器端回调+ClientsideFunction,在py文件中可用的快捷短语有:
callback-cs:oi:快速初始化具有Input和Output角色的浏览器端回调函数

callback-cs:ois:快速初始化具有Input、Output及State角色的浏览器端回调函数

在js文件中可用的快捷短语有:
callback:init:快捷生成浏览器端回调函数定义模板

3.2 常用对象在浏览器端回调中的写法
在常规的服务端回调函数中我们经常会使用到dash.no_update、PreventUpdate、dash.callback_context等对象来辅助回调函数功能逻辑的完成,而在浏览器端回调中,这些对象的写法要做一定变化:
dash.no_update
dash.no_update在浏览器端回调中写作window.dash_clientside.no_update,你也可以用feffery-dash-snippets插件中的dash.no_update快捷短语生成:

PreventUpdate
PreventUpdate在浏览器端回调中写作PreventUpdate,你也可以用feffery-dash-snippets插件中的PreventUpdate快捷短语生成(注意,在浏览器端回调中throw window.dash_clientside.PreventUpdate等价于常规回调中的raise PreventUpdate):

dash.callback_context
dash.callback_context在浏览器端回调中写作window.dash_clientside.callback_context,你也可以用feffery-dash-snippets插件中的dash.callback_context快捷短语生成:

3.3 在浏览器端回调中返回组件元素
我们在常规回调函数中,经常会以一些组件的children或其他组件型参数为Output目标,直接返回组件元素,在Python中这样做很稀疏平常,但是在浏览器端回调中,我们如果有此类需求,则需要返回规定的JSON数据格式,来表示一个组件元素:
{
props: {
// 定义当前组件的各属性,如
id: '组件id'
},
type: '组件完整名称,如AntdButton',
namespace: '组件所属组件库完整名称,如feffery_antd_components'
}
我们还是结合实际案例来做演示,这里我们的演示功能实现了通过按钮点击触发新的消息提示弹出:

具体代码如下,可以看到只要我们按照格式返回相应的组件JSON数据,Dash就会在浏览器中自动进行转换及渲染:
app4.py
import dash
from dash import html
import feffery_antd_components as fac
from dash.dependencies import Input, Output
app = dash.Dash(__name__)
app.layout = html.Div(
[
fac.AntdButton(
'新的消息',
id='new-message',
type='primary'
),
html.Div(id='new-message-container')
],
style={
'padding': '50px 100px'
}
)
app.clientside_callback(
'''(nClicks) => ({
props: {
content: "新的消息,nClicks:" + nClicks,
type: "info"
},
type: "AntdMessage",
namespace: "feffery_antd_components"
})''',
Output('new-message-container', 'children'),
Input('new-message', 'nClicks'),
prevent_initial_call=True
)
if __name__ == '__main__':
app.run(debug=True)
以上就是本文的全部内容,更多有关dash应用开发的前沿知识和技巧欢迎持续关注玩转dash公众号。
Dash应用浏览器端回调常用方法总结的更多相关文章
- [SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端
原文:[SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端 之前开发基于WinForm监控的软件,服务端基于Wcf实现,里面涉及双工模式,在客户端里面,采用心跳包机制保持与服 ...
- html5 浏览器端数据库
为什么使用浏览器端数据库:随着浏览器的处理能力不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少用户等待从服务器获取数据的时间. 一.localStorage — 本地存储 可 ...
- HTML5浏览器端图片预览&生成Base64
本文主要介绍如何通过拖拽方式在浏览器端实现图片预览,并生成图片的Base64编码. 工具链接:图片转Base64. 首先介绍一下FileReader, FileReader对象允许浏览器使用File或 ...
- Web Storage:浏览器端数据储存机制
目录 概述 操作方法 存入/读取数据 清除数据 遍历操作 storage事件 参考链接 概述 这个API的作用是,使得网页可以在浏览器端储存数据.它分成两类:sessionStorage和localS ...
- SeaJS:一个适用于 Web 浏览器端的模块加载器
什么是SeaJS?SeaJS是一款适用于Web浏览器端的模块加载器,它同时又与Node兼容.在SeaJS的世界里,一个文件就是一个模块,所有模块都遵循CMD(Common Module Definit ...
- 在浏览器端用H5实现图片压缩上传
一.需求的场景: 在我们的需求中需要有一个在手机浏览器端,用户实现上传证件照片的功能,我们第一版上了一个最简版,直接让用户在本地选择图片,然后上传到公司公共的服务器上. 功能实现后我们发现一个问题,公 ...
- 不用Blazor WebAssembly,开发在浏览器端编译和运行C#代码的网站
本文中,我将会为大家分享一个如何用.NET技术开发"在浏览器端编译和运行C#代码的工具",核心的技术就是用C#编写不依赖于Blazor框架的WebAssembly以及Roslyn技 ...
- js接收对象类型数组的服务端、浏览器端实现
1.服务端 JSONArray jsonArr = JSONUtil.generateObjList(objList); public static generateObjList(List<O ...
- 为什么commonjs不适合于浏览器端
有了服务器端模块以后,很自然地,大家就想要客户端模块.而且最好两者能够兼容,一个模块不用修改,在服务器和浏览器都可以运行. 但是,由于一个重大的局限,使得CommonJS规范不适用于浏览器环境.还是上 ...
- js IndexedDB:浏览器端数据库的demo实例
IndexedDB具有以下特点. (1)键值对储存. IndexedDB内部采用对象仓库(object store)存放数据.所有类型的数据都可以直接存入,包括JavaScript对象.在对象仓库中, ...
随机推荐
- 【译】All-In-One Search 在 Visual Studio 17.6 中可用
一体化搜索体验是在17.2预览版中首次引入的,从那以后我们一直在改进它的质量.新的搜索将代码和特性搜索功能合并到一个 UI 中,因此您可以在一个地方找到所需的东西.实时结果和结果预览加速了这个过程,让 ...
- 行行AI人才直播第15期:【AIGC科技公司法律顾问】Amber《AIGC的法律挑战》
近年来,AIGC技术的迅速进步为社会经济发展带来了新的机遇.各行各业都开始关注AIGC相关技术在商业落地中的应用,AIGC相关的创业及项目如雨后春笋般涌现.然而,AIGC的广泛应用也带来了一系列的法律 ...
- 历时数月钻研推流/对比各种流媒体服务程序/PK总结
1 前言 大量测试下来,网页显示视频流实时性从高到低依次是 webrtc > ws-flv > flv > hls.播放器打开rtsp/rtmp视频流实时性由具体的播放器控制,比如缓 ...
- TCP 粘包
TCP(Transmission Control Protocol,传输控制协议)是一种传输层协议. TCP提供了以下主要功能: 可靠性:TCP使用确认.重传和校验等机制来确保数据的可靠传输.它能够检 ...
- Cookies 完全指南
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:佳岚 前言 Cookie实际上是一小段的文本信息,它产生的 ...
- GrapeCity Documents V6.0 Update 2发布,新增支持SpreadJS的.sjs文件格式
近日,GrapeCity Documents 正式迎来其V6.2 的发布更新,能够支持 SpreadJS 中 .sjs 类型的文件.这一重大更新将为用户带来更多地惊喜. .sjs文件有两个关键优势:空 ...
- 杰哥教你面试之一百问系列:java多线程
java多线程是java面试中的高频问题,如何才能在面试中脱颖而出呢?熟读这里的一百个java多线程面试问题即可. 1. 什么是线程?什么是进程? 回答: 线程是操作系统能够进行调度的最小执行单位,它 ...
- sql-labs--Less-1--Error based-Single quotes
sql="SELECT * FROM users WHERE id='id' LIMIT 0,1"; 打开第一关,我们看到如下界面,上面写着Please input the ID ...
- React仿大众点评外卖app
主要使用技术: react react-router4 redux: action.reducer.store管理数据 fetch: 进行数据交互 prismjs : 页面嵌入代码,高亮显示插件 bu ...
- 【.NET8】访问私有成员新姿势UnsafeAccessor(上)
前言 前几天在.NET性能优化群里面,有群友聊到了.NET8新增的一个特性,这个类叫UnsafeAccessor,有很多群友都不知道这个特性是干嘛的,所以我就想写一篇文章来带大家了解一下这个特性. 其 ...