版本一,标签python化
def html_tag(tag_name):
"""创建通用 HTML 标签函数"""
def tag_func(*content, **attrs):
attr_str = " ".join(
f'{key}="{value}"' if value is not None else key
for key, value in attrs.items()
)
open_tag = f"<{tag_name} {attr_str}".strip() + ">"
close_tag = f"</{tag_name}>"
if not content:
if tag_name in {"img", "input", "br", "hr", "meta", "link"}:
return open_tag[:-1] + " />"
else:
return open_tag + close_tag
rendered_content = "".join(
item() if callable(item) else str(item) for item in content
)
return f"{open_tag}{rendered_content}{close_tag}"
return tag_func
html = html_tag("html")
head = html_tag("head")
body = html_tag("body")
div = html_tag("div")
span = html_tag("span")
p = html_tag("p")
a = html_tag("a")
img = html_tag("img")
ul = html_tag("ul")
li = html_tag("li")
h1 = html_tag("h1")
h2 = html_tag("h2")
h3 = html_tag("h3")
br = html_tag("br")
style = html_tag("style")
script = html_tag("script")
link = html_tag("link")
meta = html_tag("meta")
title = html_tag("title")
def render_html_page(title_text, body_content, styles=None, scripts=None, metas=None):
"""
生成完整的 HTML 页面。
- title_text: 页面标题
- body_content: 页面主体内容(可以嵌套组合)
- styles: 内联 CSS 或外部 CSS 链接列表
- scripts: 内联 JS 或外部 JS 链接列表
- metas: 额外的 meta 标签内容
"""
meta_tags = "".join(meta(**meta_attr) for meta_attr in (metas or []))
style_tags = "".join(
style(css) if isinstance(css, str) else link(rel="stylesheet", href=css)
for css in (styles or [])
)
script_tags = "".join(
script(js) if isinstance(js, str) else script(src=js)
for js in (scripts or [])
)
return html(
head(
meta(charset="UTF-8"),
title(title_text),
meta_tags,
style_tags
),
body(body_content, script_tags)
)
if __name__ == "__main__":
page_content = div(
h1("Welcome to My Page", class_="main-title"),
p("This is an example paragraph.", class_="description"),
a("Click me", href="https://example.com", target="_blank"),
img(src="image.png", alt="Sample Image"),
class_="content-wrapper"
)
styles = [
"""
.main-title {
color: blue;
font-size: 24px;
}
.description {
color: gray;
}
""",
"styles.css"
]
scripts = [
"""
console.log('Hello, World!');
""",
"scripts.js"
]
metas = [
{"name": "viewport", "content": "width=device-width, initial-scale=1.0"},
{"name": "author", "content": "Your Name"}
]
print(render_html_page("My Page", page_content, styles=styles, scripts=scripts, metas=metas))
版本二,考虑模块化,组件化
import uuid
class Component:
"""基础 Component 类,支持模块化样式"""
global_styles = []
def __init__(self, **props):
self.props = props
self.id = f"component-{uuid.uuid4().hex[:8]}"
def render(self):
"""渲染 HTML,子类需要实现"""
raise NotImplementedError("Subclasses must implement the render method.")
def __call__(self):
"""直接调用时返回 HTML"""
return self.render()
def get_styles(self):
"""返回组件的样式,子类可重写"""
return ""
@classmethod
def collect_styles(cls):
"""收集所有组件的样式,合并为一个字符串"""
return "\n".join(cls.global_styles)
@classmethod
def register_style(cls, style):
"""注册全局样式,避免重复"""
if style not in cls.global_styles:
cls.global_styles.append(style)
def render_children(*children):
return "".join(child() if callable(child) else str(child) for child in children)
class Div(Component):
def render(self):
class_name = self.props.get("class_", self.id)
id_name = self.props.get("id", "")
children = render_children(*self.props.get("children", []))
return f'<div class="{class_name}" id="{id_name}">{children}</div>'
def get_styles(self):
style = f"""
.{self.id} {{
padding: 10px;
border: 1px solid #ddd;
}}
"""
Component.register_style(style)
return style
class Button(Component):
def render(self):
class_name = self.props.get("class_", self.id)
text = self.props.get("text", "Button")
onclick = self.props.get("onclick", "")
return f'<button class="{class_name}" onclick="{onclick}">{text}</button>'
def get_styles(self):
style = f"""
.{self.id} {{
background-color: #007bff;
color: white;
border: none;
padding: 8px 12px;
cursor: pointer;
border-radius: 4px;
}}
.{self.id}:hover {{
background-color: #0056b3;
}}
"""
Component.register_style(style)
return style
class App(Component):
"""顶层应用组件"""
def render(self):
return Div(
class_="container",
children=[
Div(
children=[
"This is a styled container.",
Button(text="Click Me", onclick="alert('Hello!')")
]
),
Div(children=["Another styled container."]),
]
)()
def render_html_page(title, body):
styles = Component.collect_styles()
return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{title}</title>
<style>{styles}</style>
</head>
<body>
{body}
</body>
</html>"""
版本三,考虑多模块动态JavaScript交互
class Banner(Component):
def render(self):
text = self.props.get("text", "Welcome to the App")
id_ = self.props.get("id", self.id)
return f"<div id='{id_}' class='{self.props.get('class_', 'banner')}'>{text}</div>"
def get_styles(self):
style = """
.banner {
background-color: #4CAF50;
color: white;
padding: 10px;
text-align: center;
font-size: 20px;
font-weight: bold;
}
"""
Component.register_style(style)
return style
class Toolbar(Component):
def render(self):
id_ = self.props.get("id", self.id)
children = self.props.get("children", "")
return f"<div id='{id_}' class='{self.props.get('class_', 'toolbar')}'>{children}</div>"
def get_styles(self):
style = """
.toolbar {
display: flex;
gap: 10px;
padding: 10px;
background-color: #f1f1f1;
border-bottom: 1px solid #ccc;
}
.toolbar > * {
flex-shrink: 0;
}
"""
Component.register_style(style)
return style
class Table(Component):
def __init__(self, **props):
super().__init__(**props)
self.table_data = props.get("data", [["Row 1, Col 1", "Row 1, Col 2"]])
def render(self):
id_ = self.props.get("id", self.id)
return f"<table id='{id_}' class='{self.props.get('class_', 'table')}'></table>"
def get_js(self):
id_ = self.props.get("id", self.id)
return f"""
const table_{id_} = {{
data: {self.table_data},
render: function() {{
const table = document.getElementById('{id_}');
table.innerHTML = "";
this.data.forEach(row => {{
const tr = document.createElement("tr");
row.forEach(cell => {{
const td = document.createElement("td");
td.textContent = cell;
tr.appendChild(td);
}});
table.appendChild(tr);
}});
}},
addRow: function(row) {{
this.data.push(row);
this.render();
}}
}};
document.addEventListener("DOMContentLoaded", () => table_{id_}.render());
"""
def get_styles(self):
style = """
.table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.table td {
border: 1px solid #ccc;
padding: 8px;
text-align: left;
}
"""
Component.register_style(style)
return style
class Button(Component):
def render(self):
text = self.props.get("text", "Button")
onclick = self.props.get("onclick", "")
return f'<button class="{self.props.get("class_", "button")}" onclick="{onclick}">{text}</button>'
def get_styles(self):
style = """
.button {
background-color: #007bff;
color: white;
border: none;
padding: 8px 12px;
cursor: pointer;
border-radius: 4px;
}
.button:hover {
background-color: #0056b3;
}
"""
Component.register_style(style)
return style
class App(Component):
def render(self):
banner = Banner(id="app-banner", text="Dynamic Table with Toolbar")
button = Button(
text="Add Row",
onclick="table_dynamic_table.addRow(['New Row Col 1', 'New Row Col 2'])",
)
toolbar = Toolbar(id="app-toolbar", children=button())
table = Table(id="dynamic-table", data=[["Row 1, Col 1", "Row 1, Col 2"]])
return f"""
<div id="app" class="app">
{banner()}
{toolbar()}
{table()}
</div>
"""
def get_styles(self):
style = """
.app {
display: flex;
flex-direction: column;
height: 100vh;
}
.app > .banner {
flex-shrink: 0;
}
.app > .toolbar {
flex-shrink: 0;
}
.app > .table {
flex-grow: 1;
overflow: auto;
}
"""
Component.register_style(style)
return style
def get_js(self):
table = Table(id="dynamic-table", data=[["Row 1, Col 1", "Row 1, Col 2"]])
return table.get_js()
def render_html_page(title, body, scripts=""):
styles = Component.collect_styles()
return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{title}</title>
<style>{styles}</style>
<script>{scripts}</script>
</head>
<body>
{body}
</body>
</html>"""
if __name__ == "__main__":
app = App()
html_output = render_html_page("Dynamic Table with Toolbar Example", app(), scripts=app.get_js())
print(html_output)
版本四,统一js的收集
为简化和统一 JavaScript 的处理逻辑,我们可以在 Component 类中添加 collect_js 方法,与 collect_styles 类似,用于汇总所有组件的 JavaScript。这样可以确保各组件的动态行为清晰地被模块化管理。
以下是完整的代码修改,其中 collect_js 用于统一收集各组件的 JavaScript:
修改后的 Component 基类
class Component:
registered_styles = set()
registered_scripts = set()
def __init__(self, **props):
self.props = props
self.id = props.get("id", f"comp-{id(self)}")
def __call__(self, **props):
instance = self.__class__(**{**self.props, **props})
return instance.render()
def render(self):
return ""
def get_styles(self):
return ""
def get_js(self):
return ""
@classmethod
def register_style(cls, style):
cls.registered_styles.add(style)
@classmethod
def register_script(cls, script):
cls.registered_scripts.add(script)
@classmethod
def collect_styles(cls):
return "\n".join(cls.registered_styles)
@classmethod
def collect_js(cls):
return "\n".join(cls.registered_scripts)
修改后的 Table 组件
将 get_js 中的动态表格行为注册到 registered_scripts 中:
class Table(Component):
def __init__(self, **props):
super().__init__(**props)
self.table_data = props.get("data", [["Row 1, Col 1", "Row 1, Col 2"]])
def render(self):
id_ = self.props.get("id", self.id)
return f"<table id='{id_}' class='{self.props.get('class_', 'table')}'></table>"
def get_js(self):
id_ = self.props.get("id", self.id)
js_code = f"""
const table_{id_} = {{
data: {self.table_data},
render: function() {{
const table = document.getElementById('{id_}');
table.innerHTML = "";
this.data.forEach(row => {{
const tr = document.createElement("tr");
row.forEach(cell => {{
const td = document.createElement("td");
td.textContent = cell;
tr.appendChild(td);
}});
table.appendChild(tr);
}});
}},
addRow: function(row) {{
this.data.push(row);
this.render();
}}
}};
document.addEventListener("DOMContentLoaded", () => table_{id_}.render());
"""
Component.register_script(js_code)
return js_code
def get_styles(self):
style = """
.table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.table td {
border: 1px solid #ccc;
padding: 8px;
text-align: left;
}
"""
Component.register_style(style)
return style
修改后的 App 组件
App 组件自动调用各子组件的 get_js,并使用 collect_js 汇总脚本。
class App(Component):
def render(self):
banner = Banner(id="app-banner", text="Dynamic Table with Toolbar")
button = Button(
text="Add Row",
onclick="table_dynamic_table.addRow(['New Row Col 1', 'New Row Col 2'])",
)
toolbar = Toolbar(id="app-toolbar", children=button())
table = Table(id="dynamic-table", data=[["Row 1, Col 1", "Row 1, Col 2"]])
return f"""
<div id="app" class="app">
{banner()}
{toolbar()}
{table()}
</div>
"""
def get_styles(self):
style = """
.app {
display: flex;
flex-direction: column;
height: 100vh;
}
.app > .banner {
flex-shrink: 0;
}
.app > .toolbar {
flex-shrink: 0;
}
.app > .table {
flex-grow: 1;
overflow: auto;
}
"""
Component.register_style(style)
return style
修改后的 render_html_page
在 render_html_page 中调用 collect_js 来插入所有脚本。
def render_html_page(title, body, scripts=""):
styles = Component.collect_styles()
scripts = Component.collect_js()
return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{title}</title>
<style>{styles}</style>
<script>{scripts}</script>
</head>
<body>
{body}
</body>
</html>"""
完整运行示例
if __name__ == "__main__":
app = App()
html_output = render_html_page("Dynamic Table with Toolbar Example", app())
print(html_output)
关键点改进
1. 统一管理 JavaScript:
• Component.register_script 和 Component.collect_js 将所有组件的脚本整合到 App 页面中,保持模块化和可维护性。
2. 减少冗余:
• 每个组件只需要调用自己的 get_js 方法,脚本就会自动注册到全局,避免手动合并脚本。
3. 更灵活的扩展性:
• 新组件可以按需定义自己的脚本逻辑,App 无需额外处理。
4. 集中式插入脚本:
• 所有脚本在 HTML <head> 中插入,便于管理。
版本五,封装顶层render
在 React 中,最终的渲染动作通常是通过一个顶层组件(类似 App 组件)来完成的,然后通过 React 的渲染机制将其挂载到 DOM 中。这个过程与 render_html_page 类似,主要职责是将组件树组织好并渲染为完整的 HTML 结构。
以下是一些关键的 React 渲染特性,以及如何对比和设计一个类似的渲染组件:
React 渲染机制
1. 顶层组件管理:
• React 通常将顶层组件(比如 App)传递给 ReactDOM.render 或类似 API,这会生成一个完整的 DOM 树。
• 如果需要服务端渲染(SSR),可以使用 ReactDOMServer.renderToString 将组件树渲染为 HTML 字符串。
2. 渲染入口:
• React 渲染逻辑不是通过单独的函数,而是通过特定的渲染入口调用(比如 ReactDOM.createRoot)。
设计类似的组件:HTMLRenderer
如果我们希望模仿 React 的设计,可以实现一个 HTMLRenderer 组件,它专注于最终的页面渲染,包括以下职责:
1. 接收顶层组件:负责调用顶层组件并生成完整的 HTML。
2. 插入全局样式和脚本:汇总所有子组件的 get_styles 和 get_js。
3. 生成完整 HTML 页面:提供标准 HTML 结构。
以下是实现代码:
HTMLRenderer 实现
class HTMLRenderer(Component):
def __init__(self, title, body_component):
super().__init__()
self.title = title
self.body_component = body_component
def render(self):
styles = Component.collect_styles()
scripts = Component.collect_js()
body = self.body_component()
return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{self.title}</title>
<style>{styles}</style>
<script>{scripts}</script>
</head>
<body>
{body}
</body>
</html>"""
完整示例
假设我们有以下组件:
1. App:顶层应用组件,负责页面内容的组织。
2. HTMLRenderer:最终负责生成 HTML 页面。
if __name__ == "__main__":
app = App()
renderer = HTMLRenderer("Dynamic Table with Toolbar Example", app)
html_output = renderer()
print(html_output)
与 React 类比
1. HTMLRenderer 类比于 React 的服务端渲染(SSR):
• React 使用 ReactDOMServer.renderToString 来生成 HTML 字符串。
• 我们的 HTMLRenderer 模块化地生成 HTML 页面,同时整合样式和脚本。
2. 顶层组件(如 App):
• React 中 App 是主组件,所有子组件通过 JSX 嵌套。
• 在此代码中,App 是主逻辑组件,通过 Python 函数式调用嵌套其他子组件。
3. 全局样式与脚本管理:
• React 通常通过 styled-components 或 CSS Modules 管理样式,而脚本逻辑由 React 的事件绑定机制负责。
• 此设计中,组件通过 get_styles 和 get_js 明确声明其样式和脚本依赖,全局由 Component 统一收集。
灵活扩展
1. 可以扩展 HTMLRenderer 来支持更多功能,例如:
• 动态注入 Meta 标签。
• 支持 noscript 回退方案。
2. 提供更细粒度的布局控制,如头部、主体和脚部的区域划分组件。
版本六,正确划分Python和JavaScript的职责,组件双实例模式
你提到的全局状态 window.state 和 window.components 的初始化应该放在 HTMLRenderer 中,以确保它们在页面加载时被正确设置。这样做能让 HTMLRenderer 作为渲染 HTML 和 JS 代码的核心,统一初始化所有全局状态,并通过组件的 get_js 方法动态注册和更新。
我们可以调整 HTMLRenderer 类来初始化这些全局对象,并确保它在页面的 <script> 标签中定义:
重新设计的 HTMLRenderer 类
class HTMLRenderer(Component):
def __init__(self, title, body_components):
super().__init__()
self.title = title
self.body_components = body_components
def render(self):
body_html = ""
js_code = """
// 初始化全局对象
window.state = {};
window.components = {}; // 存储所有组件实例
"""
for component in self.body_components:
body_vnode = component.render()
body_html += render_vnode(body_vnode)
js_code += component.get_js()
return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{self.title}</title>
</head>
<body>
{body_html}
<script>
{js_code}
</script>
</body>
</html>"""
更新后的 JavaScript 代码
这样,每个组件的 get_js 方法将会注册自己到 window.components,并且 HTMLRenderer 会在 <script> 中提供 window.state 和 window.components 的初始化。
// 初始化全局对象
window.state = {};
window.components = {}; // 存储所有组件实例
// ButtonComponent 类定义
class ButtonComponent {
constructor(id) {
this.id = id;
}
handleClick() {
console.log('Button clicked: ' + this.id);
const tableComponent = window.components['table-component']; // 获取 Table 实例
if (tableComponent) {
tableComponent.addRow(); // 调用 Table 的方法
}
}
}
// TableComponent 类定义
class TableComponent {
constructor(id) {
this.id = id;
this.rows = [];
}
addRow() {
const newRow = { id: this.rows.length + 1, data: 'New Data' };
this.rows.push(newRow);
this.render(); // 更新表格
}
render() {
const table = document.getElementById(this.id);
const rowsHtml = this.rows.map(row =>
`<tr><td>${row.id}</td><td>${row.data}</td></tr>`
).join('');
table.innerHTML = `<thead><tr><th>ID</th><th>Data</th></tr></thead>${rowsHtml}`;
}
}
// 注册 Button 组件
window.components['button-component'] = new ButtonComponent('button-component');
// 注册 Table 组件
window.components['table-component'] = new TableComponent('table-component');
更新后的 Python Component 设计
每个组件的 get_js 方法会继续负责创建组件实例并注册到 window.components:
class Component:
def __init__(self, id=None, **props):
self.id = id or str(id(self))
self.props = props
def render(self):
raise NotImplementedError
def get_js(self):
"""为每个组件生成 JavaScript 代码,主动注册到全局的 `components` 对象"""
raise NotImplementedError
class ButtonComponent(Component):
def __init__(self, on_click=None, **props):
super().__init__(**props)
self.on_click = on_click
def render(self):
return VNode(
"button",
{"id": self.id, "onclick": self.on_click},
["Click me"]
)
def get_js(self):
return f"""
class ButtonComponent {{
constructor(id) {{
this.id = id;
}}
handleClick() {{
console.log('Button clicked: ' + this.id);
const tableComponent = window.components['table-component']; // 获取 Table 实例
if (tableComponent) {{
tableComponent.addRow(); // 调用 Table 的方法
}}
}}
}}
// 注册 Button 组件
window.components['{self.id}'] = new ButtonComponent('{self.id}');
"""
class TableComponent(Component):
def __init__(self, id, **props):
super().__init__(id=id, **props)
def render(self):
return VNode(
"table",
{"id": self.id},
[]
)
def get_js(self):
return f"""
class TableComponent {{
constructor(id) {{
this.id = id;
this.rows = [];
}}
addRow() {{
const newRow = {{ id: this.rows.length + 1, data: 'New Data' }};
this.rows.push(newRow);
this.render(); // 更新表格
}}
render() {{
const table = document.getElementById(this.id);
const rowsHtml = this.rows.map(row =>
`<tr><td>${{row.id}}</td><td>${{row.data}}</td></tr>`
).join('');
table.innerHTML = `<thead><tr><th>ID</th><th>Data</th></tr></thead>${{rowsHtml}}`;
}}
}}
// 注册 Table 组件
window.components['{self.id}'] = new TableComponent('{self.id}');
"""
总结
• HTMLRenderer 负责初始化 window.state 和 window.components,并在渲染的 <script> 中执行全局初始化代码。
• 每个组件的 get_js 方法将组件注册到 window.components,这样各个组件就可以通过该对象互相访问。
• AppComponent 和其他组件仅负责自己的渲染,JS 的初始化和事件注册都被转移到各自的 get_js 方法中。
这样,组件间的事件管理和状态更新更加灵活,并且 AppComponent 可以专注于页面的布局与组织,而所有的 JavaScript 初始化和交互逻辑由组件自身负责。
在这种设计中,Python组件的 render 方法和对应的 JavaScript组件的 render 方法之间有一个重要的区分,它们各自负责不同层面的渲染工作。我们可以通过以下几个方面来理解它们之间的关系:
1. Python 组件的 render 方法
在 Python 端,组件的 render 方法主要用于定义组件的 HTML 结构或布局。这部分工作类似于描述组件的静态内容。例如:
• ButtonComponent 的 render 可能会返回一个 <button> 元素,带有特定的属性(例如 id 和 onclick 事件处理函数)。
• TableComponent 的 render 可能会返回一个 <table> 元素,其中可能包含空的行或列。
Python 端的 render 方法并不会直接操作 DOM,也不涉及事件的绑定或动态行为。它的作用主要是返回组件的静态 HTML 结构,并确保所有的组件信息都能通过 Python 层传递到客户端(浏览器端)进行渲染。
2. JavaScript 组件的 render 方法
JavaScript 端的 render 方法负责在浏览器中动态更新 DOM。在前端,组件的 render 方法通常执行以下任务:
• 根据当前组件的状态动态地更新 DOM 元素,例如通过修改表格的行或按钮的样式。
• 绑定事件处理函数,例如将 click 事件与按钮的点击行为相关联。
在我们的设计中,JavaScript 组件的 render 方法需要依据从 Python 端传递过来的 HTML 结构来进行初始化和后续更新。因此,Python 组件的 render 和 JavaScript 组件的 render 是 解耦的,各自有不同的责任。
3. 它们之间的关系
虽然 Python 组件的 render 和 JavaScript 组件的 render 分别位于不同的层次,二者通过组件的 id 和 props 进行连接。
• Python 渲染: 当 Python 渲染组件时,它会生成一个描述该组件 HTML 结构的虚拟节点(VNode),并将其传递到客户端(浏览器)。
• JavaScript 渲染: JavaScript 则根据这些静态的 HTML 元素进行初始化,并在浏览器端负责后续的动态更新和事件处理。JavaScript 组件的 render 方法基于这些初始 HTML 元素的结构来更新或操作 DOM。
4. 动态更新与事件处理
• Python 端 只负责输出静态的 HTML 结构,不涉及与 DOM 交互的逻辑。事件绑定、状态更新等动态交互是 JavaScript 端的职责。
• JavaScript 端 使用 get_js 来注册组件实例(window.components),并通过事件处理函数(如按钮点击事件、表格行添加)来更新组件的状态和 DOM。它的 render 方法主要负责根据当前状态渲染(例如添加新的表格行、更新按钮的状态等)。
示例:
假设我们有一个 ButtonComponent 和 TableComponent。
1. Python 端 ButtonComponent 的 render:
def render(self):
return VNode(
"button",
{"id": self.id, "onclick": self.on_click},
["Click me"]
)
• 该方法会返回一个描述按钮 HTML 结构的虚拟节点(VNode)。这个节点只是一个静态的 HTML 结构,没有任何交互行为。
• 组件的 onclick 事件被传递到 Python 端的回调函数。
2. JavaScript 端 ButtonComponent 的 render:
class ButtonComponent {
render() {
const button = document.getElementById(this.id);
button.addEventListener('click', () => this.handleClick());
}
}
• render 方法在浏览器端被调用时,动态为按钮添加点击事件处理函数,执行事件响应。
• 该方法确保当用户点击按钮时,触发 JavaScript 中的相应行为(例如更新表格)。
5. 总结:
• Python 组件的 render 返回的是静态的 HTML 结构,并为每个组件提供了初始状态和属性。
• JavaScript 组件的 render 则负责动态操作 DOM,绑定事件处理程序并根据状态更新页面内容。
• Python 组件和 JavaScript 组件之间的配合 通过 id 和属性来实现,Python 渲染时返回的 HTML 结构由 JavaScript 端初始化和操作,从而实现了跨层次的组件交互。
这种设计将 Python 和 JavaScript 的职责明确分开,使得 Python 只负责静态内容的生成,而 JavaScript 负责所有的动态行为和交互,确保了两者的良好解耦并能够灵活地进行扩展和维护。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2016-11-28 工具(4): Git自助手册