streamlit实现非原生的按钮触发效果 + flask实现带信息的按钮触发

[复制链接]
发表于 2025-9-22 03:55:35 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

简介

由于streamlit可以同时在实现前后端结合,非常方便,但是这也造成了user难以方便的对页面的组件举行位置控制,本文将使用streamlit+flask,实现平凡按钮触发与携带信息
不携带信息的触发

隐蔽指定st.button(label, key)

这里给出隐蔽指定button的方法
  1. hidden_button_class = 'div[data-testid="stElementContainer"].st-key-hidden_trigger button[data-testid="stBaseButton-secondary"]'
  2. hide_button_style = f"""
  3. <style>
  4. {hidden_button_class} {{
  5.     display: none;
  6.     }}
  7. </style>
  8. """  # 如果已经使用f方法,想使用花括号就必须使用{{代替{
  9. st.markdown(hide_button_style, unsafe_allow_html=True)
复制代码
hidden_button中的st-key-hidden_trigger可以根据你的button的key举行修改
假如key = “test”, 这里就改为st-key-test,就可以实现对某个指定button的隐蔽!
固然,把.st-key-{key_name}删掉,就可以直接隐蔽所有button
触发button的html

通过在页面插入iframe,在iframe内举行JavaScript使用,实现对隐蔽button的模仿点击
  1. all_html = f"""
  2.     <script>
  3.     function handleButtonClick(event) {{
  4.         // 查找隐藏的streamlit按钮按钮
  5.         const hiddenButton = parent.document.querySelector(
  6.             'div[data-testid="stElementContainer"].st-key-hidden_trigger button[data-testid="stBaseButton-secondary"]'
  7.         );
  8.         if (hiddenButton) {{
  9.             // 触发点击
  10.             hiddenButton.click();
  11.         }}
  12.     }}
  13.     // 事件委托处理点击
  14.     document.addEventListener('click', function(event) {{
  15.         if (event.target.matches('.detail-btn')) {{
  16.             handleButtonClick(event);
  17.         }}
  18.     }});
  19.     </script>
  20.     <button class="detail-btn" data-title="test">点我</button> // 这里button的样式可以随便修改,根据需求
  21.     """
  22. st.components.v1.html(all_html)
复制代码
但是须要留意:外部的button样式对v1.html的样式不见效,内部的button样式对v1.html同样不见效
以是所有内部样式css必须写入all_html中
代码汇总

假如想要实现
  1. import streamlit as st
  2. hide_button_style = """
  3. <style>
  4. div[data-testid="stElementContainer"].st-key-hidden_trigger button[data-testid="stBaseButton-secondary"] {
  5.     display: none;
  6.     }
  7. </style>
  8. """
  9. st.markdown(hide_button_style, unsafe_allow_html=True)
  10. def generate_button():
  11.     all_html = f"""
  12.     <script>
  13.     function handleButtonClick(event) {{
  14.         // 查找隐藏按钮
  15.         const hiddenButton = parent.document.querySelector(
  16.             'div[data-testid="stElementContainer"].st-key-hidden_trigger button[data-testid="stBaseButton-secondary"]'
  17.         );
  18.         if (hiddenButton) {{
  19.             // 触发点击
  20.             hiddenButton.click();
  21.         }}
  22.     }}
  23.     // 事件委托处理点击
  24.     document.addEventListener('click', function(event) {{
  25.         if (event.target.matches('.detail-btn')) {{
  26.             handleButtonClick(event);
  27.         }}
  28.     }});
  29.     </script>
  30.     <button class="detail-btn" data-title="test">点我</button>
  31.     """
  32.     st.components.v1.html(all_html)
  33.     return
  34. generate_button()
  35. if st.button("hidden_trigger", key="hidden_trigger"):
  36.     st.success("可以修改为你想实现的功能~")
  37. st.button("no_hidden_trigger", key="no_hidden_trigger")
复制代码
css样式指定隐蔽的button
我们在点击自己设定的button后,触发了隐蔽的button,没有触发不隐蔽的button

携带信息的触发

为什么须要携带信息

假设有这么一个股票信息管理界面,很明显,假如使用streamlit原生的组件,将难以实现检察详情的按钮效果(嵌入在内容卡片中),而一支股票有很多信息(意味着更多的检察详情),为每一个检察详情都提供一个隐蔽button,会导致偶然义的内存占用,以是可以通过设置一个隐蔽按钮,并通过flask后端处置惩罚数据,接收并通报信息

前端JavaScript修改

  1. def generate_button():
  2.     all_html = f"""
  3.     <script>
  4.     function handleButtonClick(event) {{
  5.         const title = event.target.dataset.title;
  6.         // 查找隐藏按钮
  7.         const hiddenButton = parent.document.querySelector(
  8.             'div[data-testid="stElementContainer"].st-key-hidden_trigger button[data-testid="stBaseButton-secondary"]'
  9.         );
  10.         if (hiddenButton) {{
  11.             // 触发点击
  12.             hiddenButton.click();
  13.             // 发送数据到Flask
  14.             fetch('http://localhost:8000/api/data', {{
  15.                 method: 'POST',
  16.                 headers: {{
  17.                     'Content-Type': 'application/json',
  18.                 }},
  19.                 body: JSON.stringify({{title, stock}}),
  20.             }})
  21.             .then(response => response.json())
  22.             .then(data => console.log('Success:', data))
  23.             .catch(error => console.error('Error:', error));
  24.         }}
  25.     }}
  26.     // 事件委托处理点击
  27.     document.addEventListener('click', function(event) {{
  28.         if (event.target.matches('.detail-btn')) {{
  29.             handleButtonClick(event);
  30.         }}
  31.     }});
  32.     </script>
  33.     <button class="detail-btn" data-title="test">点我</button>
  34.     """
  35.     st.components.v1.html(all_html)
  36.     return
复制代码
关键在于向flask发送一个post请求,携带我们须要通报的信息(发送json串,剖析为dict)
event.target.dataset是(<button class=“detail-btn” data-title=“test”>点我</button>)中,data-title的值
以是:event.target.dataset.title = “test”
使用这个属性来通报信息
flask处置惩罚

  1. from flask import Flask, request, jsonify
  2. from flask_cors import CORS
  3. import requests
  4. app = Flask(__name__)
  5. CORS(app)
  6. @app.route('/api/data', methods=['POST'])
  7. def receive_data():
  8.     data = request.get_json()
  9.     title = process_data(data["title"])
  10.     with open("data.txt", "w", encoding="utf-8") as f:
  11.         f.write(title)
  12.     return jsonify({200: "成功"})
  13. def process_data(data):
  14.     # 数据处理逻辑
  15.     return data.upper()
  16. if __name__ == '__main__':
  17.     app.run(port=8000, debug=True)
复制代码
肯定须要CORS(),这意味着能不能实现跨域接收信息,只有加上这个才能实现网页发送信息,而flask后端能够接收网页发送的信息
同时在接收信息之后,能够将信息写入data.txt供其他文件调用(信息通报)
提示

flask的返回值是返回给客户端的,好比从客户端向flask发送了post信息,flask乐成接收后会向客户端发送jsonify({200: “乐成”}),代表了状态码200,携带值为乐成
总代码

  1. import time
  2. import streamlit as st
  3. def generate_button():
  4.     all_html = f"""
  5.     <script>
  6.     function handleButtonClick(event) {{
  7.         const title = event.target.dataset.title;
  8.         const stock = event.target.dataset.stock;
  9.         // 查找隐藏按钮
  10.         const hiddenButton = parent.document.querySelector(
  11.             'div[data-testid="stElementContainer"].st-key-hidden_trigger button[data-testid="stBaseButton-secondary"]'
  12.         );
  13.         if (hiddenButton) {{
  14.             // 触发点击
  15.             hiddenButton.click();
  16.             // 发送数据到Flask
  17.             fetch('http://localhost:8000/api/data', {{
  18.                 method: 'POST',
  19.                 headers: {{
  20.                     'Content-Type': 'application/json',
  21.                 }},
  22.                 body: JSON.stringify({{title, stock}}),
  23.             }})
  24.             .then(response => response.json())
  25.             .then(data => console.log('Success:', data))
  26.             .catch(error => console.error('Error:', error));
  27.         }}
  28.     }}
  29.     // 事件委托处理点击
  30.     document.addEventListener('click', function(event) {{
  31.         if (event.target.matches('.detail-btn')) {{
  32.             handleButtonClick(event);
  33.         }}
  34.     }});
  35.     </script>
  36.     <button class="detail-btn" data-title="test">点我</button>
  37.     """
  38.     st.components.v1.html(all_html)
  39.     return
  40. generate_button()
  41. if st.button("hidden_trigger", key="hidden_trigger"):
  42.     time.sleep(0.05)  # 让flask能够写入信息,设置一小段时间延时
  43.     with open("data.txt", "r", encoding="utf-8") as fr:
  44.         content = fr.read()  # 读取携带的信息
  45.             st.success("接收到信息:" + content)
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表