2

什么是web component

现在的前端开发几乎已经离不开组件化开发了,无论是vue中的模板语法还是react中的JSX,都是把结构、样式和逻辑封装成一个组件,采用组件复用来提高开发效率。但是这一类组件在引入后可能对页面其他代码或者样式产生影响,比如引入第三方组件库elementUI,如果页面中某个元素样式类在elementUI样式库中存在,那么这个元素的样式就会受到elementUI样式库的影响。WebComponents 是这类问题最好的良药,通过一种标准化的非侵入的方式封装一个组件,每个组件能组织好它自身的 HTML 结构、CSS 样式、javascript 代码,并且不会干扰页面上的其他代码。

开发者能通过 shadow DOM 在文档流中创建一些完全独立于其他元素的子 DOM(sub-DOM trees), 由于这个特性,使得我们可以封装一个具有独立功能的组件,并且可以保证不会在不无意中干扰到其它 DOM 元素。shadow DOM 和标准的 DOM 一样,可以设置它的样式,也可以用 javascript 操作它的行为。主文档流和基于 shadow DOM 创建的独立组件之间的互不干扰,所以组件的复用也就变得异常简单方便。

WebComponents除了是一个独立组件之外,还有一个很重要的优点,那就是WebComponents可以跨语音、跨框架使用,比如我们封装了一个WebComponent,就可以用在vue、react等框架中。

构建web compoenent

这里我们采用vue-cli3构建一个webcomponent

创建组件comA

<template>
  <div>
    <span>这是组件A</span>
    <slot name="default"></slot>// webcomponent还支持slot
  </div>
</template>

<script>
export default {
  name: 'comA',
  data() {
    return {}
  },
}
</script>

创建组件comB

<template>
  <div>这是组件B</div>
</template>

<script>
export default {
  name: 'comB',
  data() {
    return {}
  },
}
</script>

配置打包脚本

// package.json
{
  "name": "vue",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "lib": "vue-cli-service build --target wc --name foo src/components/*/*.vue"
  },
  "dependencies": {
    "core-js": "^3.4.4",
    "vue": "^2.6.10"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^4.1.0",
    "@vue/cli-plugin-eslint": "^4.1.0",
    "@vue/cli-service": "^4.1.0",
    "@vue/eslint-config-prettier": "^6.0.0",
    "babel-eslint": "^10.0.3",
    "eslint": "^5.16.0",
    "eslint-plugin-prettier": "^3.1.2",
    "eslint-plugin-vue": "^5.0.0",
    "prettier": "^1.19.1",
    "vue-template-compiler": "^2.6.10"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]
}

执行npm run lib,打包效果:
image.png
打包生成目录:
image.png
检验组件是否独立,我们往demo.html加上样式看能不能影响到comA组件

<meta charset="utf-8">
<title>foo demo</title>
<script src="https://unpkg.com/vue"></script>
<script src="./foo.js"></script>

<style>
  span {
    color: red;
  }
</style>

<span>222222222</span>
<foo-com-a><span slot="default">11111111</span></foo-com-a>

<foo-com-b></foo-com-b>

效果:
image.png
可以看到外部样式并不能影响到独立组件

分析独立组件原理

image.png
这里调用了windowcustomElements接口来注册一个 custom element
image.png
链接:https://developer.mozilla.org...

vue_wc_wrapper(external_Vue_default.a, comAshadow)// 返回一个继承HTMLElment的类,该类定义了元素行为
// external_Vue_default.a === Vue
// comAshadow自定义的vue组件

code.png

异步 Web Components 组件

当指定多个 Web Components 组件作为目标时,这个包可能会变得非常大,并且用户可能只想使用你的包中注册的一部分组件。这时异步 Web Components 模式会生成一个 code-split 的包,带一个只提供所有组件共享的运行时,并预先注册所有的自定义组件小入口文件。一个组件真正的实现只会在页面中用到自定义元素相应的一个实例时按需获取:

vue-cli-service build --target wc-async --name foo 'src/components/*.vue'
File                Size                        Gzipped

dist/foo.0.min.js    12.80 kb                    8.09 kb
dist/foo.min.js      7.45 kb                     3.17 kb
dist/foo.1.min.js    2.91 kb                     1.02 kb
dist/foo.js          22.51 kb                    6.67 kb
dist/foo.0.js        17.27 kb                    8.83 kb
dist/foo.1.js        5.24 kb                     1.64 kb

现在用户在该页面上只需要引入 Vue 和这个入口文件即可:

<script src="https://unpkg.com/vue"></script>
<script src="path/to/foo.min.js"></script>

<!-- foo-one 的实现的 chunk 会在用到的时候自动获取 -->
<foo-one></foo-one>

项目地址:https://github.com/Revelation...

参考:
https://www.cnblogs.com/vider...
https://www.cnblogs.com/Adiod...
https://developer.mozilla.org...


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。


引用和评论

0 条评论