前言
前端开发中,我们经常需要使用一些组件库来提高开发效率、提升用户体验。然而,使用现成的组件库有时会带来新的问题,如组件的样式和功能不符合需求,代码冗余严重等。因此,我们有时需要自己开发一套组件库来满足项目的具体需求。而本文将介绍一种开发自己的组件库的方法,即使用 Web Components + Vue + TypeScript 来开发。
Web Components
Web Components 是一种浏览器标准化的技术,是由自定义元素、Shadow DOM 和 HTML Template 三个规范组成的。自定义元素可以让我们自己定义 HTML 标签,Shadow DOM 可以让我们将 DOM 提供给外部,但在内部进行封装管理,HTML Template 则可以将 DOM 结构提前预定义好,使得使用方只需要将数据传入即可。
通过 Web Components,我们可以封装我们的组件,并提供一个正式的API来使用。具体来说,我们可以通过以下步骤开发一个 Web Component:
- 使用
customElements.define()
方法创建一个自定义元素。 - 在自定义元素的类里面使用 Shadow DOM 来封装我们的组件。
- 将组件的样式和行为封装在自定义元素的类里面。
- 在 HTML 中使用我们的组件。
如果要想更深入了解 Web Components 的细节,可以参考 MDN 文档。
Vue
Vue 是一个渐进式框架,它可以帮助我们构建复杂的应用程序界面。Vue 在 React 和 Angular 的基础上发展而来,它具有易于学习、灵活和高性能等特点。通过使用 Vue,我们可以方便地开发复杂的组件,Vue 组件也可以与 Web Components 自然集成。
TypeScript
TypeScript 是 JavaScript 的一个超集,它可以给 JavaScript 添加静态类型检查和一些其他的语言特性,如类、模块等。通过 TypeScript 能够使我们编码更加规范、代码更加清晰。Vue 和 Web Components 都可以使用 TypeScript 进行开发。
实践
在了解了 Web Components、Vue 和 TypeScript 之后,我们接下来将介绍如何使用它们来开发自己的组件库。
创建一个简单的 Web Component
在开始 Vue 和 TypeScript 的开发之前,我们先来熟悉一下 Web Components 的开发。我们将创建一个简单的 hello-world
组件来演示。
创建一个 hello-world.ts
文件,其中代码如下:
class HelloWorld extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: 'open' }); const p = document.createElement('p'); p.innerText = 'Hello World'; shadow.appendChild(p); } } customElements.define('hello-world', HelloWorld);
在这个文件中,我们创建了一个 HelloWorld
类,继承自 HTMLElement
。我们通过 customElements.define()
方法将这个自定义元素注册到浏览器中,并起名为 hello-world
。
在 HelloWorld
的构造函数中,我们首先调用 super()
来调用父类的构造函数,然后将组件内部的元素封装到 Shadow DOM 中,并将 Hello World
文字展示在一个 p
元素中。
接下来,我们在 HTML 文件中引入这个 hello-world.js
文件,并在需要使用的位置添加 hello-world
自定义元素。例如:
<!DOCTYPE html> <html> <head> <title>Hello World Example</title> <script src="hello-world.js"></script> </head> <body> <hello-world></hello-world> </body> </html>
我们可以看到,这样我们就创建了一个简单的 Web Components,可以在 HTML 中使用。
在 Vue 中使用 Web Component
接下来让我们来介绍如何在 Vue 中使用 Web Component。
我们将使用 Vue CLI 创建一个新的项目。在创建项目时,可以选择使用 TypeScript 来进行开发。
在 src/components
目录下创建一个 HelloWorld.vue
文件,其中代码如下:
<template> <hello-world /> </template> <script lang="ts"> import { Vue, Component } from 'vue-property-decorator'; import HelloWorld from '@/components/hello-world'; @Component export default class HelloWorldVue extends Vue { mounted() { customElements.define('hello-world', HelloWorld); } } </script>
在这个文件中,我们使用了 Vue 的 @Component
注解来定义了一个 HelloWorldVue
类,并在其中通过 @vue-property-decorator
的 mounted
钩子方法来定义了一个自定义元素。在 mounted
中,我们通过 customElements.define()
方法注册了一个名为 hello-world
的自定义元素,并将其关联到了具体的实现类 HelloWorld
上。
此外,我们在这个文件中的模板中也使用这个 hello-world
自定义元素,这样,我们就将 hello-world
结合到了 Vue 的组件中,可以在 Vue 项目中使用了。
开始开发组件库
有了以上的铺垫,我们就可以开始开发组件库了。我们的组件库将包含一个 button
组件和一个 modal
组件。
开发 Button 组件
我们在 src/components
目录下创建一个 Button.vue
文件,其中代码如下:
<template> <button :class="classes" :disabled="disabled" @click="clickHandler"><slot /></button> </template> <script lang="ts"> import { Vue, Component, Prop } from 'vue-property-decorator'; @Component export default class Button extends Vue { @Prop(String) readonly type!: string; @Prop({ default: false }) readonly disabled!: boolean; get classes() { return `btn ${this.type || ''}`; } clickHandler() { this.$emit('click'); } } </script> <style> .btn { border: none; border-radius: 4px; padding: 8px 16px; font-size: 14px; cursor: pointer; } .btn-primary { background-color: #2077f5; color: #fff; } .btn-primary:hover { background-color: #1859c0; } .btn-danger { background-color: #f5222d; color: #fff; } .btn-danger:hover { background-color: #cf1322; } </style>
在这个文件中,我们定义了一个 Button
类,并使用 @vue-property-decorator
来修饰为 Vue
组件。我们使用 @Prop
来定义了 type
和 disabled
两个属性,并使用 get classes()
方法返回样式类。在模板中,我们将 disabled
属性和 click
事件直接绑定到了 button
标签上,并在其中使用了 slot
插槽将按钮的文字内容提供出去。
此外,在样式中,我们也定义了两种不同类型的按钮,分别为 btn-primary
和 btn-danger
,并为其设置了不同的样式。
开发 Modal 组件
我们在 src/components
目录下创建一个 Modal.vue
文件,其中代码如下:
<template> <div class="modal" :class="{ 'is-active': visible }"> <div class="modal-background" @click="closeHandler" /> <div class="modal-content"> <slot /> </div> <button class="modal-close" aria-label="close" @click="closeHandler" /> </div> </template> <script lang="ts"> import { Vue, Component, Prop, Watch } from 'vue-property-decorator'; @Component export default class Modal extends Vue { @Prop({ default: false }) readonly visible!: boolean; @Watch('visible', { immediate: true }) visibleChanged(newValue: boolean) { if (newValue) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } } closeHandler() { this.$emit('update:visible', false); } } </script> <style> .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 9999; display: none; } .modal.is-active { display: flex; justify-content: center; align-items: center; } .modal-background { background-color: rgba(0, 0, 0, 0.5); position: absolute; top: 0; left: 0; right: 0; bottom: 0; } .modal-content { background-color: #fff; border-radius: 4px; padding: 24px; max-height: 90%; overflow: auto; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); width: 80%; } .modal-close { background-color: transparent; border: none; position: absolute; top: 0; right: 0; width: 40px; height: 40px; display: flex; justify-content: center; align-items: center; font-size: 24px; color: #999; cursor: pointer; } </style>
在这个文件中,我们定义了一个 Modal
类,并使用 @vue-property-decorator
来修饰为 Vue
组件。我们使用 @Prop
来定义了 visible
属性,并使用 watch
监听 visible
的变化来控制 body
滚动条的显示。在模板中,我们根据 visible
属性的值来动态控制 .modal
样式类的显示。我们还定义了一个 closeHandler
方法来控制 Modal
的关闭。
此外,在样式中,我们设置了 Modal
的样式,并将 .modal-close
样式定义为了不可见的状态。
使用组件
我们在 src/components
目录下创建一个 index.ts
文件,其中代码如下:
import Vue from 'vue'; import HelloWorldVue from './hello-world.vue'; import Button from './button.vue'; import Modal from './modal.vue'; const Components = { HelloWorldVue, Button, Modal, }; Object.keys(Components).forEach((name) => { Vue.component(name, Components[name]); }); export default Components;
在这个文件中,我们导出了三个组件,分别为 HelloWorldVue
、Button
和 Modal
,并将这些组件注册到了 Vue 组件中。
最后,在我们的 Vue 项目中使用这些组件非常简单,例如在 App.vue
中使用 Button
组件:
<template> <div id="app"> <h1>My Vue Component Library</h1> <Button type="btn-primary" @click="showModal" :disabled="disabled">Show Modal</Button> <Modal v-model="showingModal" /> </div> </template> <script lang="ts"> import { Vue, Component } from 'vue-property-decorator'; import { Button, Modal } from '@/components'; @Component({ components: { Button, Modal, }, }) export default class App extends Vue { disabled = false; showingModal = false; showModal() { this.showingModal = true; } } </script> <style> #app { text-align: center; } h1 { font-size: 30px; margin-top: 60px; } </style>
在这个文件中,我们首先导入了 Button
和 Modal
组件,并在 @Component
的 components
属性中注册这些组件。然后在模板中使用 Button
组件来触发 showModal
方法,同时传递了 type
和 disabled
两个属性。最后,我们又在模板中使用了 Modal
组件,并通过 v-model
来绑定 showingModal
属性的值,从而控制 Modal
组件的显示和隐藏。
总结
Web Components、Vue 和 TypeScript 是相互独立的技术,但是它们可以相互结合,让我们更加高效地开发 Web 应用。通过本文中的实践,我们了解了如何使用 Web Components 、Vue 和 TypeScript 来开发组件库,以及如何将这些组件集成到 Vue 项目中。最终,我们实现了一个包含 Button
和 Modal
两个组件的组件库。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65acbd0fadd4f0e0ff651b93