原生javascript组件开发之Web

北京的哪个医院治白癜风好 http://www.bdfyy999.com/index.html
前言

作为一名前端工程师,我们每天都在和组件打交道,我们也许基于act/vue使用过很多第三方组件库,比如antdesign,elementUI,iView等,或者基于它们进行过组件的二次开发,比如业务组件,UI组件等,亦或者觉得团队能力很强,可以不依赖第三方而独立开发属于自己的组件库。无论何种形式,组件开发已然成为我们工作中的必备技能,为了更好的复用性和可维护性,组件化开发是必然选择,也正是因为组件化开发越来越重要,几年前web标准推出了WebComponent这一概念,意在解决html原生标记语言复用性的问题。

目前vue或者act框架中也支持使用WebComponent,而且在WebComponent中也可以动态的调用act或者vue的api来实现组件或页面的渲染,这给我们开发者提供了更大的自由度,从而在日益复杂的项目中能使用更加灵活且优雅的方式来进行组件化开发。

我们使用WebComponent可以通过原生的方式来实现组件化而不依赖与vue或者act这些第三方框架,并且现代浏览器对其支持还算不错,相信未来WebComponent将会成为组件开发的趋势。所以接下来笔者将会带大家一步步来学习WebComponent,并且使用WebComponent实现两个常用组件:

ButtonModal大家在掌握了WebComponent之后可以开发更多自定义组件,那么写下来就来学习一下吧。正文在开始正文之前笔者还想多啰嗦一下,也是之前有很多朋友问我的问题:如何在公司平衡好工作和成长?其实笔者也经历过这种迷茫期,之前因为公司业务繁忙而不得不忙于编写业务代码,几乎没有时间去学习和成长。有些时候项目做完之后又有新的需求要处理,感觉瞬间被掏空。(B端产品为了满足客户需求往往在产品把控上很难做取舍,因为客户就是上帝,所以工程师和产品的关系很微妙~)

一般情况下遇到以上的情景,作为一个合格的企业员工的,当然是业务和任务优先,在完成工作之后再去考虑成长和学习。当然公司也不会一直这么忙,所以当空闲的时候,我们可以好好利用(当然偶尔刷刷手机也是允许的,取决于个人)。

另一方面,我们可以通过提高工作效率来压缩工作时间,因为业务代码做多了总会有点规律和总结,如果整体架构设计的好,一般第一次做过了,第二次再遇到类似的业务几乎“秒关”,这一块对于前端来说,组件系统和模块化尤其重要;对于后端来说,微服务是很好的例子。

所以说如何学习和成长,以上两点是笔者3年工作的总结,希望能给大家以启发。

另一个问题就是如何快速掌握新技术?这个答案在这篇文章结束后,大家也许会明白些许。

好了,废话到此为止,接下来进入我们的WebComponent实战。笔者对其知识点梳理成如下的思维导图:1.WebComponent基础知识

WebComponents主要由三项技术组成,分别为

Customelements(自定义元素)ShadowDOM(影子DOM)HTMLtemplates(HTML模板)它们可以一起使用来创建功能强大的定制元素,并且可以在我们喜欢的任何地方重用,不必担心代码冲突。接下来笔者就分别介绍这三项技术。1.1Customelements(自定义元素)

customelements也就是我们常说的自定义标签,它主要通过CustomElementRegistry接口来定义,CustomElementRegistry.define(name,class,extends)方法用来注册一个customelement,该方法接受以下参数:

name所创建的元素名称,且需符合DOMString标准的字符串。注意,customelement的名称不能是单个单词,且其中必须要有短横线class用于定义元素行为的类extends可选参数,一个包含extends属性的配置对象,指定了所创建的元素继承自哪个内置元素,可以继承任何内置元素。具体案例如下:

customElements.define(word-count,classWordCountextendsHTMLParagraphElement{constructor(){super();//元素的功能代码...}},{extends:p});

接下来另一个比较重要的知识点就是customelement的生命周期回调函数,具体介绍如下:

connectedCallback:当customelement首次被插入文档DOM时,被调用disconnectedCallback:当customelement从文档DOM中删除时,被调用adoptedCallback:当customelement被移动到新的文档时,被调用attributeChangedCallback:当customelement增加、删除、修改自身属性时,被调用大家可以先理解一下生命周期函数的用法,在下面的组件实战中会有详细的应用。1.2ShadowDOM(影子DOM)

ShadowDOM接口可以将一个隐藏的、独立的DOM附加到一个元素上,并且允许将隐藏的DOM树附加到常规的DOM树中:以shadowroot节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的DOM元素一样。MDN对其有一张详细的草图方便大家理解:

上图中4个术语意思如下:

Shadowhost:一个常规DOM节点,ShadowDOM会被附加到这个节点上。Shadowte:ShadowDOM内部的DOM树。Shadowboundary:ShadowDOM结束的地方,也是常规DOM开始的地方。Shadowroot:Shadowte的根节点如果我们想将一个ShadowDOM附加到customelement上,可以在customelement的构造函数中添加如下实现:

classButtonextendsHTMLElement{constructor(){super();letshadow=this.attachShadow({mode:open});}}

我们将ShadowDOM附加到一个元素之后,可以使用DOMAPIs对它进行操作,如下:

classButtonextendsHTMLElement{constructor(){super();letshadow=this.attachShadow({mode:open});letpara=document.cateElement(p);shadow.appendChild(para);}}

我们甚至可以将样式插入到ShadowDOM中,如下:

letstyle=document.cateElement(style);style.textContent=`.btn-wrapper{position:lative;}.btn{//...}`shadow.appendChild(style);

以上是定义组件的最基本方式,一个完整的demo如下:

classButtonextendsHTMLElement{constructor(){super();letshadow=this.attachShadow({mode:open});letpara=document.cateElement(p);shadow.appendChild(para);letstyle=document.cateElement(style);style.textContent=`.btn-wrapper{position:lative;}.btn{//...}`shadow.appendChild(style);}}customElements.define(xu-button,Button);

1.3HTMLtemplates(HTML模板)

template和slot元素可以用来灵活填充Web组件的shadowDOM的模板.它们的使用很简单,有点类似于vue的template和slot。一个简单的tempalte例子如下:

templateid="xu_tpl"p趣谈前端/p/template

我们可以用JavaScript获取它的引用,然后添加到DOM中,代码如下:

lettemplate=document.getElementById(xu_tpl);lettemplateContent=template.content;document.body.appendChild(templateContent);

至于slot,使用和vue的slot有点类似,主要提供一种插槽机制,比如我们在模版中定义一个插槽:

templateid="xu_tpl"pslotname="xu-text"趣谈插槽/slot/p/template

我们可以这么使用slot:

xu-buttonspanslot="xu-text"趣谈前端,让前端更有料!/span/xu-button

介绍完基本概念之后,我们开始实战开发。

2.WebComponent组件开发实战在开发之前,我们先来看看实现效果:

第一张图是我们的自定义按钮组件(Button),图二是笔者实现的弹窗(modal)组件。感觉还算有模有样,我们只需要引入这几个组件,即可在项目中使用,代码的目录结构如下:

接下来我们就开始实现它们吧。2.1Button组件实现

我们像任何vue或者act组件一样,在设计组件之前一定要界定组件的边界和功能点,笔者在之前的从0到1教你搭建前端团队的组件系统(高级进阶必备)也有系统的介绍,这里就不在介绍了。

我们实现一个可以定制主题并且可以插入任意内容的Button组件,利用上面将的知识点,要实现插入自定义内容,我们可以使用template和slot,首先定义template和slot,代码如下:

templateid="btn_tpl"slotname="btn-content"buttoncontent/slot/template

要想首先自定义按钮主题,我们可以通过props来实现用户控制,就像antd的Button组件,支持primary,warning等类型,具体实现如下:

//Button.jsclassButtonextendsHTMLElement{constructor(){super();//获取模板内容lettemplate=document.getElementById(btn_tpl);lettemplateContent=template.content;constshadowRoot=this.attachShadow({mode:open});constbtn=document.cateElement(button);btn.appendChild(templateContent.cloneNode(true));btn.setAttribute(class,xu-button);//定义并获取按钮类型primary

warning

defaultconsttype={primary:#06c,warning:d,default:#f0f0f0}constbtnType=this.getAttribute(type)

default;constbtnColor=btnType===default?#:#fff;//创建样式conststyle=document.cateElement(style);//为shadowDom添加样式style.textContent=`.xu-button{position:lative;margin-right:3px;display:inline-block;padding:6px20px;border-radius:30px;background-color:{type[btnType]};color:{btnColor};outline:none;border:none;box-shadow:inset05px10pxrgba(0,0,0,.3);cursor:pointer;}`shadowRoot.appendChild(style);shadowRoot.appendChild(btn);}}customElements.define(xu-button,Button);

?

在构造函数中,我们会定义元素实例所拥有的全部功能。通过用户传入的type属性来在Button组件挂载前设置其类型。对于自定义的插槽,我们可以通过template.content来获取其内容,然后插入shadowRoot中使其拥有slot能力。具体使用如下:xu-buttontype="primary"spanslot="btn-content"id="btn_show"趣谈button/span/xu-buttonxu-buttontype="warning"spanslot="btn-content"趣谈button/span/xu-buttonxu-buttontype="default"spanslot="btn-content"趣谈button/span/xu-button

?

我们的Button组件拥有大部分原生dom的能力,包括dom操作,事件等,如下所示我们给自定义Button添加点击事件:

document.querySelector(#btn_show).addEventListener(click,()={modal.setAttribute(visible,true);},false)

?

2.2Modal组件实现

Modal组件的实现和Button原理类似,不过过程稍微复杂一点,我们需要考虑Modal内容的插槽,Modal的显示和隐藏的控制等,如下图所示:

具体的dom实现细节笔者就不一一介绍了,大家可以有不同的实现。我们主要来


转载请注明:http://www.guyukameng.com/html/html1/12720.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了