ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Brython browser.webcomponent 模块:用 Python 定义自定义 HTML 标签与 Web Components 实战指南

Brython browser.webcomponent 模块:用 Python 定义自定义 HTML 标签与 Web Components 实战指南 编程语言语言运行时编译器前端【免费下载链接】brythonBrython (Browser Python) is an implementation of Python 3 running in the browser项目地址https://gitcode.com/gh_mirrors/br/brython点击查看免费下载本指南系统讲解 BrythonBrowser Python标准库中browser.webcomponent模块的完整用法如何基于标准 DOM 的 Web ComponentsCustom Elements技术用纯 Python 定义自定义 HTML 标签、管理组件生命周期、监听属性变化并动态创建组件实例。读完本文你将掌握define()/get()两个核心 API、extends继承机制的两种写法、Shadow DOM 封装技巧以及connectedCallback/attributeChangedCallback等生命周期回调的 Brython 实现方式。模块概述用 Python 驾驭 Web Components 标准browser.webcomponent是 Brython 暴露标准 DOMWeb Component自定义元素能力给 Python 的桥接模块。Web Components 是一组浏览器原生技术允许开发者注册新标签使浏览器在遇到这些标签时执行指定类的方法。在 Brython 中这意味着你可以完全用 Python 类描述组件的结构与行为而无需编写一行 JavaScript。模块对应的 Python 文件为 www/src/Lib/browser/webcomponent.py其内容仅有一行from _webcomponent import *真正的实现位于底层 JS 模块 www/src/libs/_webcomponent.js通过customElements.define()等浏览器原生 API 完成注册。一个自定义元素在 HTML 页面中这样使用popup-windowHello !/popup-window只要该标签已通过define()注册了对应的 Python 类浏览器就会按你的类定义来创建和渲染这个元素。API 速览define 与 get模块对外暴露两个函数函数签名作用definedefine(tag_name, component_class[, options])注册自定义标签将标签名与组件类绑定getget(tag_name)返回与标签名关联的组件类若未注册则返回None其中define()是核心入口参数语义如下tag_name自定义标签的名称。Web Component 规范强制要求标签名中必须包含一个连字符-如popup-window、bold-italic这是为了与未来 HTML 新增的内置标签区分。component_class定义组件行为的 Python 类。当浏览器在文档中遇到该标签时会调用类的__init__方法完成创建此时self参数引用的就是该自定义元素的 DOM 节点因此你可以在__init__中直接操作self.attrs、self.style、self.attachShadow(...)等 DOM 接口。options可选字典对应标准CustomElementRegistry.define()的选项。目前可用的唯一选项是extends用于声明组件基于某个内置 HTML 元素扩展。define() 深入命名规则与参数校验从源码 www/src/libs/_webcomponent.js 可以看到define()在注册前会执行严格的参数校验这与浏览器规范保持一致tag_name必须是字符串否则抛出TypeError如果字符串中不包含-抛出ValueError错误信息为custom tag name must contain a hyphen (-)。component_class必须是类isinstance(cls, type)否则抛出TypeError。options只能是None或字典其他类型抛出TypeError。校验通过后模块会做两件事一是给 Python 类打上$webcomponent true标记并把DOMNode插入类的 MRO若尚未存在使组件实例获得 Brython DOM 节点的全部能力运算符、attrs、bind()等二是生成一个继承自HTMLElement的 JavaScript 类其构造器负责调用 Python 类的__init__并将 MRO 中所有函数型属性包括各基类的方法逐一绑定到原型上包装成调用 Python 方法的闭包。最终通过customElements.define(tag_name, webcomp)完成注册。extends 的两种用法显式传入与自动推导extends选项对应 Web Components 的自定义内置元素customized built-in element机制即让自定义标签继承某个原生 HTML 元素的行为。它有两种指定方式方式一显式传入 optionsclass MyParagraph: def __init__(self): self.shadow self.attachShadow({mode: open}) self.shadow html.B(hello) define(my-paragraph, MyParagraph, {extends: p})这里{extends: p}表示my-paragraph是p段落元素的定制版本。方式二继承 browser.html 中的类自动推导如果组件类继承了 browser.html 模块中定义的类extends选项会被自动添加其值取该基类的类名小写。因此上面的代码可以改写为from browser import html class MyParagraph(html.P): def __init__(self): self.shadow self.attachShadow({mode: open}) self.shadow html.B(hello) define(my-paragraph, MyParagraph)这种方式更符合 Python 的直觉——组件本质上就是html.P的一个子类继承关系即声明了扩展目标。源码中对这一机制的处理逻辑是当options为None时遍历类的tp_bases基类链找到第一个__module__ browser.html的基类将其类名小写后作为extends值。此外无论哪种方式传入的extends都会进一步校验它必须是字符串且document.createElement(extends)的结果不能是HTMLUnknownElement否则抛出ValueErrorxxx is not a valid tag name。实战示例用 Shadow DOM 构建bold-italic组件设想我们要定义一个带data-val属性的自定义标签bold-italicbold-italic>from browser import webcomponent class BoldItalic: def __init__(self): # Create a shadow root shadow self.attachShadow({mode: open}) # Insert the value of attribute data-val in bold italic # in the shadow root shadow html.B(html.I(self.attrs[data-val])) # Tell the browser to manage bold-italic tags with the class BoldItalic webcomponent.define(bold-italic, BoldItalic)注意这里使用了另一项 DOM 技术——ShadowRoot影子根。self.attachShadow({mode: open})会在组件内部建立一棵独立于主 DOM 树的子树主文档中的 CSS 选择器默认无法穿透进入这棵子树从而实现了组件的样式与结构封装。shadow html.B(html.I(...))是 Brython 的 DOM 插入语法等价于向影子根追加一个bi.../i/b节点属性值则通过self.attrs[data-val]读取。生命周期回调connectedCallbackWeb Components 技术定义了一组生命周期回调函数lifecycle callbacks用于在组件的不同阶段执行逻辑。在 Brython 中实现它们非常简单只需要在类定义中直接添加同名方法即可模块会把这些方法从 Python 类桥接到生成的 JavaScript 类原型上import browser.webcomponent class BoldItalic: def __init__(self): # Create a shadow root shadow self.attachShadow({mode: open}) # Insert the value of attribute data-val in bold italic # in the shadow root shadow html.B(html.I(self.attrs[data-val])) def connectedCallback(self): print(connected callback, self) webcomponent.define(bold-italic, BoldItalic)connectedCallback在自定义元素被插入文档时触发是执行初始化如读取子节点、绑定事件、加载数据的推荐位置。test_webcomponent.py中大量使用了这一回调例如用_initialized标志保证只初始化一次或在回调中访问self.children、self.parentNode、self.attrs完成组件间的配置传递。标准的生命周期回调还包括disconnectedCallback元素被移出文档、adoptedCallback元素被移动到新文档等均可按同样方式实现。监听属性变化observedAttributes 与 attributeChangedCallback若要响应组件某些属性的变化需要在类中声明类属性observedAttributes要监听的属性名列表并实现attributeChangedCallback()方法。注意下面的示例创建了一个全新的自定义元素并且是用browser.html模块的maketag函数创建、动态添加到文档中的observed_tag html.maketag(observed-element) class Observed: observedAttributes [data] def attributeChangedCallback(self, name, old, new, ns): print(fattribute {name} changed from {old} to {new}) webcomponent.define(observed-element, Observed) elt observed_tag() document elt elt.attrs[data] info执行流程是html.maketag(observed-element)在browser.html模块中生成一个名为observed-element的标签工厂函数调用它创建元素实例eltdocument elt将元素插入文档触发connectedCallback随后修改elt.attrs[data] info浏览器检测到被观察属性变化自动回调attributeChangedCallback(data, old, new, ns)打印出变化前后的值。从源码看observedAttributes支持三种形态普通列表推荐、property属性装饰器见 issue 2454 的用例以及已废弃的方法形式会触发DeprecationWarning。在 www/gallery/webcomponent.html 的完整示例中Child组件同时实现了observedAttributes [data]与attributeChangedCallback并配合一个#change_data按钮在运行时修改属性将变化记录写入页面。动态创建组件html.maketag上文出现的html.maketag(tagName)是browser.html模块提供的标签工厂机制其实现位于 www/src/brython.js。要点如下参数必须是字符串否则抛出TypeError。如果browser.html模块中已经存在同名标签类抛出ValueErrorcannot reset class for ...防止覆盖已有标签。它会创建一个新的标签类、对应的工厂函数并注册进browser.html模块的tags字典随后即可像html.DIV(...)一样用observed_tag(...)构造实例。这正是「先define一个组件类再用maketag在 Python 侧动态生成该组件实例并插入 DOM」这一组合玩法的基础适合在纯 Python 逻辑中按需创建组件而非依赖 HTML 源码中预先写好的标签。源码级原理解析底层如何工作define()的底层实现www/src/libs/_webcomponent.js值得深入了解它揭示了 Brython 类与浏览器自定义元素类之间的桥接细节JS 类生成模块通过字符串模板生成一个继承HTMLElement或extends目标元素的原型构造器的 JS 类类名与 Python 类同名其constructor先调用super()再查找 Python 类的__init__并调用同时把self包装为 Brython 的DOMNode实例。属性合规检查若组件此前已初始化webcomp.initialized构造器会对比__init__执行前后的attributes列表——按照 HTML 规范自定义元素的构造器不允许擅自新增属性违反时抛出TypeError。方法桥接遍历 Python 类 MRO 中所有类的字典把每个函数型属性若 JS 原型上尚无同名属性包装为调用 Python 方法的闭包挂到 JS 原型上——这就是connectedCallback、attributeChangedCallback等 Python 方法能被浏览器生命周期系统调用的原因。observedAttributes 静态 getter映射到 Python 类上的同名属性支持列表与property两种取值方式。注册最终调用customElements.define(tag_name, webcomp, {extends: ...})或customElements.define(tag_name, webcomp)完成注册。相应地get(name)的实现在底层就是调用customElements.get(name)若返回的类带有 Brython 标记$cls则返回对应的 Python 类否则返回None。仓库中的验证与扩展示例仓库为这一模块提供了丰富的验证与演示资源可作为进阶参考单元测试www/tests/test_webcomponent.py约 400 行覆盖了多继承组件issue 1893、生命周期回调中的异常处理issue 1894、基类方法调用issue 2082、通过__init_subclass__钩子自动注册组件issue 2169、继承html.DIV的组件PR 2295以及注册表 un_camel自动生成标签名issue 2447 / 2454等场景。完整演示页www/gallery/webcomponent.html 展示了从 MDN 经典popup-info弹出提示组件、bold-italic、父子组件继承parent-component/child-component、observed-element属性监听到基于__init_subclass__的ui-page自动注册体系以及bind/unbind、addEventListener/removeEventListener在组件内的事件绑定对比等一整套实践。测试注册入口www/tests/brython_test_utils/init.py 将test_webcomponent.py注册为 Web component 测试组说明该模块已纳入 Brython 常规回归测试。注意事项与限制标签名必须包含连字符且不能与browser.html中已有的标签重名maketag会拒绝重置已有标签。自定义元素的构造阶段__init__不得新增属性否则会触发合规性错误初始化逻辑应尽量放在connectedCallback中完成。当组件类继承browser.html中的类时extends自动推导的优先级低于显式传入的options——若两者同时存在以显式options为准。observedAttributes推荐使用类属性列表写法方法写法已废弃并会收到DeprecationWarning。本文所述行为以当前仓库源码为准使用时请确保浏览器支持 Web ComponentsCustom Elements / Shadow DOM标准。赞分享编程语言语言运行时编译器前端【免费下载链接】brythonBrython (Browser Python) is an implementation of Python 3 running in the browser项目地址https://gitcode.com/gh_mirrors/br/brython点击查看免费下载相关推荐10分钟出第一个视频ComfyUI-WanVideoWrapper文生视频——用81帧上下文窗口做WanVideo视频生成10分钟出第一个视频ComfyUI WanVideoWrapper文生视频——用81帧上下文窗口做WanVideo视频生成 ComfyUI WanVideoW编程语言语言运行时编译器前端Brython 自定义 Web 组件实战用 browser.webcomponent 打造属于自己的 HTML 标签Brython 自定义 Web 组件实战用 browser.webcomponent 打造属于自己的 HTML 标签 browser.webcomponent编程语言语言运行时编译器前端torsniff性能优化实战如何将种子嗅探效率提升300%torsniff性能优化实战如何将种子嗅探效率提升300% torsniff是一款强大的BitTorrent网络种子嗅探工具能够从海量P2P网络中捕获用户正上一篇Novate 开源项目实战指南下一篇从0到1构建基于NuExtract的智能信息抽取系统架构设计与最佳实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表