什么是webComponents
Web Components 是一种使用原生的js、html、css创建自定义组件的技术。相比于其他组件化框架,比如 Vue、React等,它具有体积小、不用加载其他外部模块的优势。
如何使用webComponents
- 自定义组件都是由类声明的,我们需要先定义一个类:
class Btn extends HTMLElement {
constructor () {
super()
}
}
- 使用 shandow DOM 将组件与外部隔离,防止组件内部样式影响到组件外元素的样式,然后使用原生 js 语法添加元素及样式:
class Btn extends HTMLElement {
constructor () {
super()
// 使用 shadow Dom 将组件隔离,防止样式穿透
const shadowDom = this.attachShadow({ mode: "open" })
this.p = this.h('button')
this.p.innerText = '自定义按钮'
this.p.setAttribute('style', 'border: none; background-color: pink; height:30px;')
shadowDom.appendChild(this.p)
}
h(el) {
return document.createElement(el)
}
}
- 使用 window.customElements.define() 注册自定义组件,根据规范,自定义组件的名称必须包含连词线,用与区别原生的 HTML 元素。
window.customElements.define('my-btn', Btn)
- 直接在html中使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webComponents</title>
<script src="./btn.js"></script>
</head>
<body>
<my-btn></my-btn>
</body>
</html>
使用template 风格声明自定义组件
如果觉得上面的写法比较麻烦,我们可以使用template来声明自定义组件:
class templateBtn extends HTMLElement {
constructor () {
super()
const shadowDom = this.attachShadow({ mode: "open" })
this.template = this.h('template')
this.template.innerHTML = `
<button>自定义template风格按钮</button>
<style>
button{
border: none;
background-color: khaki;
height: 30px;
margin: 5px;
border-radius: 6px;
}
</style>
`
shadowDom.appendChild(this.template.content.cloneNode(true))
}
h(el) {
return document.createElement(el)
}
}
window.customElements.define('temp-btn', templateBtn)
Web Components 生命周期
web components 定义的组件有以下几个生命周期钩子:
// webComponents 生命周期
// 挂载后
connectedCallback () {
console.log('挂载了');
}
// 断开后
disconnectedCallback () {
console.log('断开了');
}
// 被移动到新文档时
adoptedCallback () {
console.log('被移动了');
}
// 自定义元素的属性被增加、修改、删除时
attributeChangedCallback () {
console.log('属性改变了');
}
自定义组件传递DOM属性
自定义组件可以像原生html元素那样使用 DOM attribute,由于 DOM attribute 只能为字符串类型的值,所以设置复杂类型的值时,需要使用 JSON.stringify() 将引用类型的值转为字符串,使用的时候再 JSON.parse() 转为引用类型。
<body>
<my-btn></my-btn>
<br>
<temp-btn a="123"></temp-btn>
<br>
<button>原生btn</button>
<script>
const tempBtn = document.getElementsByTagName('temp-btn')[0]
const a = {abc: 1}
tempBtn.setAttribute('obj', JSON.stringify(a))
const obj = tempBtn.getAttribute('obj')
console.log(JSON.parse(obj).abc); // 1
</script>
</body>
在Vue3中使用 Web Components
- 在 vite.config.ts 中进行配置:
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag:any) => tag.includes('my-')
}
}
})
]
})
- 新建一个自定义组件,必须要以 .ce.vue 为后缀:
<template>
<button>
自定义按钮
</button>
</template>
<script setup lang='ts'>
const props = defineProps<{
obj: any
}>()
console.log(props.obj);
</script>
<style scoped>
button{
height: 30px;
background-color: skyblue;
border: 1px solid #ccc;
border-radius: 10px;
}
</style>
- 在父组件中引入,并使用vue 提供的 defineCustomElement 方法来创建自定义组件
<template>
<div>
<my-btn :obj="obj"></my-btn>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, defineCustomElement} from 'vue'
import customVueCeVue from './components/custom-vue.ce.vue'
const Btn = defineCustomElement(customVueCeVue)
window.customElements.define('my-btn', Btn)
const obj = {name: '张三'}
</script>
更多详细用法请查看 Vue 官网: Vue 与 Web Components