当前位置: 首页 > 科技观察

十分钟让你入门WebComponents

时间:2023-03-16 14:43:50 科技观察

什么是webcomponents组件封装是我们前端一直在讨论的一个话题。但是现在我们的组件库更多是基于某个框架来实现的,比如Vue的ElementUI,React的ANTD。这种组件的缺点是对外部框架的依赖。您必须基于Vue或React使用它。如果哪天项目迁移了,你得重写一套。能不能基于原生的HTML/CSS/JS来封装一个组件规范?那就是Web组件。WebComponents本身不是一个单独的规范,而是一组DOMAPI和HTML规范,用于创建可直接在您的Web应用程序中使用的具有自定义名称的可重用HTML标签。组件定义和核心目标我认为组件是一种内部抽象,封装了一定的逻辑功能,并将相关接口暴露给外部调用。它可以完成以下功能:Reuse:组件将作为一个可重用的单元在多个地方使用。解耦:组件本身隔离变更,组件开发人员和业务开发人员可以按照组件的约定独立开发和测试。封装:组件屏蔽了内部细节,组件的使用者只关心组件的属性、事件和方法。抽象:组件通过属性、事件、方法等基础设施提供了一种统一的描述UI的模式,降低了用户学习的心理成本。那么WebComponents是如何做到以上几点的呢?WebComponents的核心概念主要有以下几点:自定义元素(customelements):一组JavaScriptAPI,允许您定义自定义元素及其行为,然后在您的用户界面中根据需要使用它们。ShadowDOM:一组JavaScriptAPI,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制它们的相关功能。这样,您可以将元素的功能保密,这样就可以编写脚本和设置样式,而不必担心与文档的其余部分发生冲突。HTML模板:这里要注意几点:template可以理解为一个普通的div,但该元素中的所有内容都不会直接显示在界面上。style标签可以直接插入template标签中,style在模板内部定义。:host伪类用于定义shadow-root的样式,即包裹这个模板的标签的样式。注意占位符。稍后可以使用您自己的标记语言填充此占位符,我们将在后面提到。它的用法和Vue的slot一样。应该说是Vue借鉴了它的实现。自定义元素使用CustomElementRegistry.define()方法注册您的新自定义元素,将要定义的元素的名称、指定元素功能的类以及它继承自的元素(可选)传递给它。自定义元素的名称,一个DOMString标准字符串,为了防止与自定义元素冲突,必须是带连字符的名称(如custom-tag)。这也是推荐的使用Vue自定义组件命名的方式。构造函数。包含组件生命周期定义的自定义元素构造函数。扩展参数(可选),参数类型为对象,需要包含extends属性,用于指定创建的元素继承自哪个内置元素(如{extends:'p'})。代码如下:classUserCardextendsHTMLElement{constructor(){//必须调用super();极好的();//创建一个影子节点,其他创建的元素应该附加到这个节点上varshadow=this.attachShadow({mode:"closed"});//获取模板实例vartemplateElem=document.getElementById("userCardTemplate");//复制一下,因为页面上的模板不是一次性的,其他组件也可以参考varcontent=templateElem.content.cloneNode(true);//this.getAttribute可以获取组件的参数内容.querySelector("img").setAttribute("src",this.getAttribute("image"));//添加Go到shadowdomshadow.appendChild(content);}}//注册自定义元素window.customElements.define("user-card",UserCard);这里需要注意一点:Class类必须调用super()。获取到模板后,需要通过clone()方法进行复制,因为页面上的模板不是一次性的,还可能引用其他组件。this.getAttribute可以获取传递给组件的参数。定义完成后,我们可以直接使用user-card自定义元素,并且可以给组件传递属性,可以通过slot标签指定name属性,使用我们在上面HTML模板中定义的占位符。Gopal

1172597655@qq.com

最终组件效果如下:ShadowDOM上面的demo已经实际使用过了,我们可以在任何节点内部创建一个ShadowDOM。获取元素实例后,调用Element.attachShadow()方法为元素附加一个新的影子根。该方法接受一个只有一个mode属性的对象,值为open或closed,表示是否可以从外部获取到ShadowDOM中的节点。上面我们将其设置为关闭。如果改成open,结果如下:虽然所面临的挑战早就提出来了,但WebComponents的流行度远不如Vue、React等框架的组件库。主要问题是Vue、React等框架帮我们解决了一些视图渲染逻辑,比如React,使用JSX和Css模块,我们只需要关心数据状态,不需要更多关注HTML模板像WebComponents,它带来了更多的灵活性和便利性。总结与思考精读《Web Components 的困境》[2]总结中提到:WebComponents作为浏览器的底层特性,不应该与React、Vue等应用层框架相提并论。WebComponents提供的方向和价值将与应用程序框架不一致。而WebComponents作为未来的Web组件标准,可以很好地运行在任何生态系统中。我更期待应用层能做更多基于WebComponents的实现,让组件可以超越框架存在,可以在不同的技术栈中使用。诚然,React和WebComponents也可以共存,React官方文档也提到它是为解决不同的问题而诞生的。WebComponents为可重用组件提供强大的封装,而React提供声明式解决方案来保持DOM和数据同步。两者旨在相互补充。作为开发人员,您可以自由选择将React与WebComponents结合使用,或将WebComponents与React结合使用,或两者兼而有之。至于应用层做更多基于WebComponents的实现,我觉得这是一个比较理想的状态。毕竟React和Vue如果要封装自己基于WebComponents的实现,那么WebComponents需要做更灵活的规范和标准,期待这一天的到来。参考精读《Web Components 的困境》[3]WebComponentsMDN[4]WebComponents入门指南[5]参考资料[1]Demo地址:https://codepen.io/gpingfeng/pen/zYRMagp。[2]精读《Web Components 的困境》:https://juejin.cn/post/6844903494885851149。[3]精读《Web Components 的困境》:https://juejin.cn/post/6844903494885851149。[4]Web组件MDN:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components。[5]Web组件入门指南:https://segmentfault.com/a/1190000039269731。