栏目导航

伟易博娱乐官网
www.veb88.com
伟易博娱乐网址

Web 组件势必代替前端?

发布时间: 2019-07-09

  我建立了一个Web组件,能够懒加载图像,只要图像完全呈现正在浏览器的窗口中时才进行加载。代码正在Github()上。

  还记得document.querySelector第一次获得浏览器的普遍支撑,终结了jQuery一统全国的场合排场的时辰吗?

  例如,若是组件中有个id=container,而你需要正在属性disabled发生改变时,将这个元素设置为灰色布景,那么需要正在constructor中援用该属性,如许它才能呈现正在attributeChangedCallback中:

  正在通过customElements.define注册之后,该元素就会通过类定义获得加强。该过程称为“升级”(upgrading)。能够正在元素被升级时通过customElements.whenDefined挪用一个回调函数,该方式前往一个Promise,正在元素被升级时该Promise获得处理:

  另一点很主要的是,要认识到你能够正在通过customElements.define注册Web组件之前就利用它。当元素存正在于DOM中,或者被插入到DOM中时,若是它还没有被注册,那么它将成为HTMLUnknownElement的实例。浏览器会对于任何它不认识的HTML元素的处置方式是,你仍然能够像利用其他元素那样利用它,只是它没有任何方式,也没有默认的样式。

  正在浏览器的开辟者东西中,组件将显示为单个HTML标签,所有的样式和行为都完全被封拆,不需要任何额外的技巧,不需要框架,也不需要编译。

  现正在,Web组件曾经获得了普遍的支撑,你也许能够看出,原生代码能够供给取框架媲美的功能,但机能更好,代码量更小,复杂度更低。

  若是需要正在HTML属性(attribute)发生变化时施行一些动做,那么能够将其插手到observedAttributes数组中。为了机能,只要插手到这个数组中的属性(attribute)才会被。当HTML属性(attribute)的值发生变化时,attributeChangedCallback就会被挪用,同时传入HTML属性的名称、当前值和新值:

  建立影子root之后,就能够正在利用所有DOM的方式,就像泛泛处置document对象那样,如利用this.shadowRoot.querySelector来查找元素。组件的所有CSS都能够定义正在style标签中,但也能够通过凡是的link rel=stylesheet来读取外部样式表。除了一般的CSS之外,还能够利用:host选择器给组件本人定义样式。例如,自定义元素默认利用display: inline,利用下面的CSS能够将其定义为块元素:

  取connectedCallback相对的就是disconnectedCallback,当元素从DOM中移除时会挪用该方式。正在这个方式中能够进行需要的清理工做,但要记住这个方式不必然会被挪用,好比用户封闭浏览器或封闭浏览器标签页的时候。

  jQuery及其优异的遗产仍然会继续存正在一段时间,但现正在很少有新项目再利用它们,由于我们有了更好的选择。我并不认为现正在的框架会很快消逝,但做为更好的选择,原生Web组件曾经呈现,并且敏捷获得了关心。我认为,这些前端框架的脚色也会改变,它们会正在原生Web组件的根本上供给一个简单的层。前往搜狐,查看更多

  留意,正在扩展已有元素时不克不及利用影子DOM。这仅仅是通过承继所有属性、方式和事务并供给额外的功能来扩展原生HTML的方式。当然,正在组件内部点窜元素的DOM和CSS是可能的,但试图建立影子root则会抛犯错误。

  我们自定义元素的类只是通俗的Java类,它扩展了原生的HTMLElement。除了构制函数之外,它还有个方式叫做connectedCallback,当元素被插入到DOM树之后该方被挪用。你能够认为它相当于React的componentDidMount方式。

  有史以来我们第一次可以或许仅通过HTML、CSS和Java建立组件并正在任何现代浏览器上运转。现正在,最新版本的Chrome、Sari、Firefox和Opera桌面版,以及Sari的iOS版、Chrome的Android版都支撑Web组件。

  有了这些框架,我们就能完成一些一曲想做但一曲没法子实现的工作——建立可沉用的从动化前端组件。然而,这些框架会添加复杂性,添加专有的语法,还会增大承担。

  扩展已有HTML元素的益处是,它能承继所有的属性和方式。如许就能够渐进式加强已有元素,因而即便浏览器不支撑自定义元素,该元素也是可用的,它只不外是采用默认的内置行为。而若是撰写全新的HTML标识表记标帜,正在不支撑自定义元素的浏览器中就完全无法利用了。

  也就是说,若是想按照特定属性的值,正在影子DOM中设置装备摆设任何结点,那就需要正在constructor中援用属性,而不克不及正在connectedCallback中进行。

  前端框架的另一个经常被提及的益处就是,它们供给了尺度的代码,团队中的每个新都能从一起头就很熟悉。我相信这是准确的做法,但我也认为这个益处很是无限。

  Java也能够处置slot,能够查看某个slot被分派了什么结点,查看某个元素被分派到了哪个slot,还能够利用slotchange事务。

  还有个adoptedCallback方式,当通过document.adoptNode(element)将元素收养至文档中时会挪用该方式。到目前为止,我从来没碰到过需要利用该回调函数的环境。

  这些元素现实上是video元素的影子DOM的一部门,因而默认是躲藏的。要正在Chrome中显示影子DOM,能够正在“偏好设置”中的开辟者东西中找到设置,勾选“显示用户代办署理的影子DOM”。正在开辟者东西中从头查抄video元素,就能看到元素的影子DOM。

  我曾正在多个项目中利用过Angular、React和Polymer,虽然它们之间有类似性,但即便是利用统一个框架,代码布局也会截然不同。一个清晰的工做体例和样式指南,为代码供给的分歧性远远好于仅依赖框架。框架也会带来额外的复杂性,所以该当问问本人如许做能否值得。

  属性次要用于定义元素的初始设置装备摆设和初始形态。理论上通过序列化的体例给属性传送复杂的值,但这会对机能形成很大影响,并且因为你可以或许拜候组件的方式,所以如许做是没有需要的。但若是确实但愿像React、Angular等框架供给的功能那样,正在属性上实现数据绑定,能够看看Ploymer()。

  要给影子root添加HTML,能够将HTML字符串赋值给影子root的innerHTML属性,也能够利用template元素。HTML模板根基上是一段HTML片段,供当前利用。正在插入到DOM树中之前,它不成见,也不会被解析,也就是说其内部定义的任何外部资本都不会被下载,任何CSS和Java正在插入到DOM之前也不会被解析。例如,你能够定义多个template元素,当组件的HTML按照组件形态而发生变化时,将响应的模板插入到DOM中。如许就能够很容易地改变组件的大量HTML,而不需要逐一处置DOM结点。

  这段代码正在定义影子root时利用了mode: open,其寄义是它能够通过开辟者东西进行查看和操做,能够查询,也能够设置装备摆设任何的CSS属性,也能够它抛出的事务。影子root的另一个模式是mode: closed,但这个选项不保举利用,由于利用者将无法取组件进行人和交互,以至都不克不及其抛出的事务。

  原生的Web组件(还)不供给如许的功能,虽然曾经有提案扩展template元素以支撑利用数据进行初始化和更新:

  利用影子DOM,自定义元素的HTML和CSS能够完全封拆正在组件内部。这意味着正在文档的DOM树中,元素会显示为单一的HTML标签,其现实内部HTML布局会呈现正在#shadow-root中。

  测试Web组件很是容易、间接,取Angular、React等框架比拟,测试Web组件简曲是小菜一碟。不需要任何编译,也不需要复杂的设置。只需建立元素,添加到DOM中,然后运转测试即可。

  另一个常用的生命周期方式是attributeChangedCallback。当属性被添加到observedAttributes数组时该方被挪用。该方式挪用时的参数为属性的名称、属性的旧值和新值:

  能够利用webcomponents-loader.js,该文件会进行功能检测,只要正在需要时才会加载polyfill。利用polyfill就能够利用自定义元素,而不需要改动源代码。可是,它并不克不及供给实正的CSS范畴,意味着若是分歧的Web组件中的元素具有同样的class名和id,它们将会冲突。并且,影子DOM的CSS选择器:host和:slotted可能无法准确工做。

  回忆一下,Web组件的属性的次要目标是初始化设置装备摆设。也就是说,当组件被插入到DOM中时,设置装备摆设该当曾经被初始化过了,所以attributeChangedCallback该当正在connectedCallback之前被挪用。

  带有name属性的slot元素称为定名slot,但该属性并不是必需的。name属性只是用来将内容衬着到特定的。若是一个或多个slot没有name属性,内容将会按照利用者供给的挨次进行衬着。若是利用者供给的内容少于slot的个数,slot还能够供给默认内容。

  这里两个模板都通过innerHTML放到了影子root内。一起头时两个模板都是躲藏的,只要容器被衬着。正在connectedCallback内我们挪用this.shadowRoot.querySelector(#view1).content.cloneNode(true)获取了#view1的内容。模板的content属性前往的模板内容为DocumentFragment实例,该实例能够通过添加到另一个元素中。因为正在元素已存正在于DOM中的环境下会挪动元素,所以我们起首需要利用cloneNode(true)来复制它。不然,模板的内容将会被挪动而不会被添加,意味着我们只能利用其内容一次。

  可是,任何影子DOM内部的结点抛出的事务则不会冒泡到影子DOM外面,除非它是利用composed: true建立的:

  有一点很主要:外部定义正在组件上的样式的优先级要高于正在影子DOM中利用:host定义的样式。因而,若是定义了:

  外部不成能给自定义元素内部的任何元素定义样式。但若是但愿利用者可以或许给组件(中的部门元素)定义样式,那么能够通过CSS变量来实现。例如,若是但愿利用者能选择组件的布景颜色,那么能够名为--background-color的CSS变量。

  虽然这一流程完全有事理,但会让更新一小部门DOM的操做变得很麻烦,而React和Angular的描述性体例更容易。这些框架能够定义一个包含表达式的视图,正在表达式发生变化时进行更新。

  Web组件(Web Component)的概念最后于2011年提出,组件包罗一系列功能,能够仅通过HTML、CSS和Java就能建立可沉用的组件。也就是说,建立组件不需要再利用React或Angular之类的框架。更妙的是,这些组件还可以或许无缝地集成到这些框架中。

  Webpack加载器完成三项工做:它给Web组件的影子DOM中的所有不是以::host或::slotted开首的CSS法则添加前缀,前缀为元素的名称,从而供给准确的范畴。之后,它会解析所有::host和::slotted法则,它们准确工做。

  正在现代Web API的成长下,建立可沉用的前端组件终究不再需要框架了。有了自定义元素和影子DOM,我们就能够建立可以或许随便复用的组件。

  现实上,好几个原生HTML元素也正在利用影子DOM。例如,若是正在网页上放置一个video元素,它会显示为单一的标签,但同时显示的播放、暂停按钮等正在开辟者东西中查看video元素时是看不到的。

  除了生命周期方式之外,你还能够正在元素上定义方式,这些方式能够从外部挪用。这个功能是React和Angular等框架无法实现的。例如,你能够定义一个名为doSomething的方式:

  组合就是将影子DOM树取利用者供给的标识表记标帜言语组合正在一路。slot元素能够实现这一过程,能够认为它是影子DOM中的一个占位符,利用者供给的标识表记标帜言语将正在此处衬着。利用者供给的标识表记标帜言语称为“轻量DOM”(light DOM)。组合过程将轻量DOM和影子DOM连系正在一路,构成新的DOM树。

  扩展内置元素的另一个益处就是,它能够用于元素父子关系的环境。例如,thead元素仅答应tr元素做为子结点,那么利用awesome-tr元素将被视为不法标识表记标帜。这种环境下我们能够扩展内置的tr元素,并如许利用:

  默认环境下,自定义元素会从四周的CSS承继一些属性,如color、font等。可是若是你但愿从全新的形态起头,使组件的所有CSS属性沉置到默认值,能够如许做:

  想要让这两个选择器准确工做,你需要加载Shady CSS polyfill,还需要(少量)点窜源代码。我小我不喜好这一点,所以我写了个Webpack加载器来帮你实现这一点。这意味着你需要编译代码,但不再需要点窜源代码了。

  如许利用Web组件能够带来很是好的渐进式加强,但正如前面所说,目前只要Chrome和Firefox支撑。Edge未来也会支撑,但正在本文撰写之时,Sari并不支撑。

  例如,你能够建立一个image-gallery组件,利用该组件时,供给两个尺度的img标签供组件衬着用:

  影子DOM还支撑实正的CSS范畴(scope)。所有定义正在组件内部的CSS只对组件本身无效。元素仅从组件外部定义的CSS中承继最小量的属性,以至,连这些属性都能够设置装备摆设为不承继。可是,你能够一些CSS属性,答应组件的利用者给组件添加样式。这种机制处理了现有的CSS的很多问题,同时仍然支撑自定义组件的样式。

  每当slot内部的结点发生变化(结点被添加或删除)时会发生slotChange事务。留意该事务仅正在slot结点本身上触发,而不会正在slot结点的子元素上触发。

  该回调函数仅正在属性存正在于observedAttributes数组中时才会被挪用,正在上例中为foo和bar。任何其他属性的变化不会挪用该回调函数。

  ::slotted能够接管任何无效的CSS选择器,但只能选择顶层结点。例如,::slot(section img)正在这种环境下无法利用:

  模板正在需要快速改变一HTML或沉用HTML的环境下很是有用。模板也不限于Web组件,能够用正在DOM中的任何处所。

  Edge将鄙人一个版本(版本19)中支撑Web组件。旧版本浏览器还可利用polyfill(),最低能正在IE11上实现Web组件。

  除了定义Web组件的初始形态之外,HTML属性(attribute)还用来反映响应的组件属性(property)的值,因而元素的Java形态能够反映到其DOM暗示中。下面的例子演示了input元素的disabled属性:

  这里,第一行导入了my-element.js,该文件将Web组件为ES6模块。这就是说,测试文件也需要做为ES6组件加载到浏览器中。因而,需要正在浏览器中利用下面的html文件来运转测试。除了Mocha之外,我们还加载了WebcomponentsJS polyfill,还有Chai用于测试断言,还有Sinon用于(spy)和模仿(mock):

  影子DOM内部通过slot衬着的元素称为分派结点。这些结点的样式会正在衬着到组件内部的影子DOM(即“分派”)后仍然无效。正在影子DOM内部,分派结点还能够通过::slotted选择器获得额外的样式:

  当前的前端框架通过数据绑定、形态办理和很是尺度化的代码带来了良多额外的价值。问题就是你的使用法式能否需要这些。

  加载完必需的脚本之后,我们chai.assert为全局变量,如许就能够正在测试中简单地通过assert进行断言,并设置Mocha利用BDD接口。接下来加载测试文件(本例中只要一个),然后挪用mocha.run运转测试。

  数据绑定也许会给你带来益处,但Web组件曾经支撑间接将属性设置为数组、对象等非简单值了。简单值能够通过HTML属性(attribute)来设置,属性的改变能够通过atributeChangedCallback来。

  MyElement构制函数必需是ES6类,然而很倒霉的是,因为Java类分歧于保守的OOP言语的类,这很容易形成紊乱。并且,由于这里能够利用Object,所以Proxy也是可行的,如许就能正在自定义元素上实现简单的数据绑定。可是,若是想实现对原生HTML元素的扩展,这个是必需的,如许才能你的元素可以或许承继整个DOM API。

  该组件将接管两个图像,并正在组件的影子DOM内部衬着。留意图像上的slot=image属性。该属性告诉组件图像正在影子DOM中衬着的。影子DOM的样子可能如下:

  该按钮被我们的MyElement类加强。若是它加载到不支撑自定义元素的浏览器中,它就会变成通俗的按钮。这是实正的渐进式加强!

  这是个用来演示原生Web组件的很是好的例子:只需要导入Java文件,添加HTML标签或操纵is扩展已有的原生标签就能够了!

  若是你不清晰使用法式能否实的需要Redux等形态办理,那么很大可能你并不需要。需要时你必定会感遭到。

  到目前为止,我们一曲正在扩展HTMLElement来建立全新的HTML元素。自定义元素还能够用来扩展内置的原生元素,从而实现对图像、按钮等已有HTML元素的加强。正在撰写本文时,该功能仅Chrome和Firefox支撑。

  define方式的第一个参数是要建立的新元素的标签名称。接下来,你只需要下面的代码就能够利用该元素:

  任何正在元素上定义的属性城市成为它的公开Java API的一部门。如许,只需给元素的属性供给setter,就能够实现数据绑定,从而实现雷同于正在元素的HTML里衬着属性值等功能。由于原生的HTML属性(attribute)值仅支撑字符串,因而对象等复杂的值该当做为自定义元素的属性(properties)。

  除了利用this.shadowRoot.innerHTML给影子root中的元素添加HTML之外,还能够利用template来实现这一点。模板用来供给一小段代码供当前利用。模板中的代码不会被衬着,初始化时它的内容会被解析,但仅仅用来其内容是准确的。模板内部的Java不会被施行,任何外部资本也不会被获取。默认环境下它是躲藏的。

  留意,正在利用ES6模块时,还需要将mocha.run放正在带有type=module的内。这是由于默认环境下ES6模块是被延迟加载的,若是mocha.run正在一般的标签内,它将正在my-element.test.js加载之前被施行。

  通过对CSS和HTML范畴(scope)的支撑,影子DOM处理了CSS的全局性带来的问题——会导致庞大的、只能添加的样式表,此中的选择器的法则越来越具体,充满了各类笼盖。影子DOM使得开辟者能够将标识表记标帜言语和样式打包到组件内部,而不需要任何东西或定名法则。如许就不消担忧新的class或id会取已有的冲突。

  select元素就利用了这种体例,你能够正在Chrome的开辟者东西中查看(若是你勾选了“显示用户代办署理的影子DOM”选项,如上文所示):

  自定义元素发生的尺度事务(如鼠标和键盘事务等)默认环境下会从影子DOM中冒泡出来。若是事务从影子DOM内部的结点发生,那么它的方针会被从头设置,使之看起来像是从自定义元素本身发生的。若是想晓得事务到底发生于影子DOM中的哪个元素,能够挪用osedPath来获取该事务颠末的一系列结点。可是,事务的target属性永久指向自定义元素本身。

  你能够建立自定义的HTMl标签,它可以或许从被扩展的HTML元素那里承继所有的属性,然后只需要简单地导入一段脚本,就能够正在任何支撑Web组件的浏览器中利用。组件中定义的所有HTML、CSS和Java的定义域都仅限于组件内部。

  一般来说,组件的设置该当尽可能低推迟到connectdedCallback中进行,由于这是唯逐个个可以或许确保所有属性和子元素都存正在的处所。一般来说,构制函数该当仅初始化形态,以及设置影子DOM(Shadow DOM)。

  可见,用户供给的带有slot属性的元素将被衬着到slot元素内部,slot元素的name属性值必需婚配响应的slot属性的值。

友情链接:
Copyright 2018-2022 https://www.handan101.com All Rights Reserved. 版权所有