本文示例程式碼已上傳至我的
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公眾號。