前端笔记:使用Web Components进行原生组件化开发 | 您所在的位置:网站首页 › 原生组件库 › 前端笔记:使用Web Components进行原生组件化开发 |
文章目录
目的基础说明技术点介绍Custom elementsShadow DOMHTML templates
整合成独立组件文件示例演示与说明示例一示例二
es6-string-html总结
目的
前端开发中组件化开发是一种趋势,方便界面中各种自定义组件的管理与复用。现在流行的 React 和 Vue 等框架都是组件化开发的。目前前端原生也支持一定程度上的组件化开发,这个称为Web Components,这篇文章将对相关内容做个说明。 Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的web应用中使用它们。 基础说明原生的HTML标准中提供很多的组件,比如 p 、div 、button 这些,这些元素的默认样式和功能都朴素简单了,通常使用时我们需要根据功能需求再编写很多样式和脚本,大多数时候我们甚至需要将一些空间嵌套组合使用。这样的开发对于这些自己设计的组件的管理、维护、复用等工作都是比较麻烦的。 比较方便的一种方式是所有组件相关的html和css代码都封装到js中,这样每个组件就是一份js代码了,使用时只要调用相关函数将传教组件插入到DOM中就行。目前前端原生的组件化开发最根本的也是用js,再此基础上针对组件化需求添加了一些新特性。这整一个被称为Web Components。 Web Components主要有 四部分 三部分 组成: Custom elements(自定义元素)Shadow DOM(影子DOM)HTML templates(HTML模板)HTML Imports(HTML导入) 前面几部分编写的代码放一个html文件中就成了一个单文件的组件,可以使用HTML Imports功能在正式页面中导入组件的html文件来使用组件;这个东西现在被废弃了,目前还没有非常好的代替这个功能的东西; 技术点介绍Web Components 中涉及的一些技术可以在MDN上找到说明: https://developer.mozilla.org/zh-CN/docs/Web/Web_Components Custom elements这东西就是组件化开发的核心了,用来创建自定义组件。这个其实很简答,创建一个继承自HTMLElement的类就行: class YourComponent extends HTMLElement { constructor() { super(); // 组件的功能代码写在这里 } }接下来我们需要使用 CustomElementRegistry.define() 方法将上面的类和一个自定义的标签绑定,这样你就可以在页面中直接使用这里的标签来使用自定义的组件了: customElements.define('your-component', YourComponent); // 官方规定自定义标签必须大于一个单词,单词间用-连接将两者结合一下就是下面的样子: customElements.define('your-component', class extends HTMLElement { constructor() { super(); // 组件的功能代码写在这里 } } );知道上面两点内容后就可以创建自己的组件来使用了: 上图演示中用上了自定义的标签元素,这个内部元素内部其实就是在声明的类中用js代码创建的。上面演示中自定义组件内部的内容是在类中写死的,实际上我们希望属性是可以在使用时自由设置的。可以通过下面方式来自由设置属性: 除了上面的基础用法Custom elements还有一些生命周期相关的回调函数可用: customElements.define('your-component', class extends HTMLElement { static get observedAttributes() { return ['要监听的属性列表'] } // 配合下面attributeChangedCallback()使用 constructor() { super(); } connectedCallback() {} // 当组件首次被插入文档DOM时被调用 disconnectedCallback() {} // 当组件从文档DOM中删除时被调用 adoptedCallback() {} // 当组件被移动到新的文档时被调用 attributeChangedCallback(name, oldValue, newValue) {} // 当组件增加、删除、修改自身属性时被调用 } ); Shadow DOM这东西主要用于让组件内的各个元素和DOM隔离,这样自定义的组件才能真正成为独立的组件,不会被页面中其它样式等的污染。 在上一节其实我们已经实现了自定义组件,但是这里还存在一个比较大的问题。上面的自定义组件内部的各种元素对外都是可见的,这会引起很多问题,比如内部的元素会被外部样式所修改。这时候就要用到Shadow DOM了: 上面的 attachShadow() 中mode参数可以设置为 closed 或 open ,区别在于页面中JS对shadow DOM内部元素的访问性: 前面内容中创建组件用的都是JS,但只用JS来创建组件的话组件的结构和样式稍微复杂点就变得很麻烦了,这个时候要用上HTML templates了,它可以让你用原生html、css、js语言来编写组件。HTML templates结合前面的内容使用时差不多是下面这样的结构: customElements.define('your-component', class extends HTMLElement { constructor() { super(); let template = document.getElementById('your-component-template'); let templateContent = template.content; const shadowRoot = this.attachShadow({ mode: 'closed' }); shadowRoot.appendChild(templateContent.cloneNode(true)); // 克隆template内部内容添加到ShadowDOM中 } } );
除了上面的基础使用外HTML templates还提供了一个更进一步的功能slot。这东西可以让你在templates的html结构中插入一个插槽,这样你在使用自定义组件的时候可以向这个插槽中插入各种各样的东西:
上面演示中组件和页面都是在同一个文件中的,实际使用中我们通常是希望组件可以封装在独立的文件中的。 在HTML Imports弃用之前我们可以把组件相关的代码(比如template、script)这些写到一个html文件中,然后在真实页面头部中使用 方式引用组件。 在HTML Imports已经被废弃并且ES Module还无法import html文件的现在我们只能把template部分代码作为字符串嵌入到js代码中来使用了。最终组件就是一个独立的js文件,比如下面这样: 需要注意的是下面演示中JS使用了ES module的方式,该方式必须使用服务器,最简单的比如VS Code中安装Live Server扩展来处理。 示例一 export default class YourComponent extends HTMLElement { static get observedAttributes() { return ['color'] } constructor() { super(); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = ` :host { color: ${this.color}; } `; } get color() { return this.getAttribute('color') || 'blue'; // 如果没有设置颜色则返回bule作为默认颜色 } set color(value) { this.setAttribute('color', value); } connectedCallback() { this.text = this.shadowRoot.getElementById('text'); } attributeChangedCallback(name, oldValue, newValue) { if (name == 'color' && this.text) { this.text.style.color = newValue; } } } if (!customElements.get('your-component')) { customElements.define('your-component', YourComponent); }
上面演示中对于color这个属性,可以通过组件标签中添加属性来设置,也可以在页面上用CSS进行设置,另外虽然上面没有演示,其实也可以通过js使用 color(value) 或 setAttribute(name,value) 方法来设置。 示例二 export default class YourComponent extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = ` :host>.btn { width: 5rem; height: 2rem; line-height: 2rem; margin: 0.2rem; font-size: 1.25rem; text-align: center; } :host(:not([type="ok"]):not([type="error"]))>.btn { color: blue; } :host([type="ok"])>.btn { color: white; background-color: green; } :host([type="error"])>.btn { color: white; background-color: red; } :host>.btn:hover { opacity: 0.6; } :host>.btn:active { opacity: 0.2; } :host-context(.round)>.btn { border-radius: 0.5rem; } `; } } if (!customElements.get('your-component')) { customElements.define('your-component', YourComponent); }
上面把模板的代码当作字符串来处理最终用是能用了,但是代码编写、修改的时候就比较纠结了。好在在VScode中可以安装es6-string-html扩展在一定程度上改善这个问题: 安装该插件后只要在字符串前面加上 /*html*/ 就可以以Html形式渲染字符串内容,编写和修改上也一般的代码编写差不多。目前来说唯一没法实现的就是格式化操作。 总结Web Components 使用总体来说并不复杂。就我个人而言比起Vue、React这类需要编译的框架,我更加喜欢浏览器原生就能解析使用的开发方式。 更多内容可以参考MDN相关的例程: https://github.com/mdn/web-components-examples 另外也可以参考第三方的原生组件库: https://github.com/XboxYan/xy-ui |
CopyRight 2018-2019 实验室设备网 版权所有 |