前言:这周完成了两场技术分享会,下周还有一场,就完成了这阶段的一个重大任务。分享会是关于 TS 的,我这两场分享会的主题分别是:
- TS 初级入门
- TS 高级语法
下周的主题是,如何在 React 中优雅的书写 TS。
我对技术也是有那么点喜欢,所以我平时喜欢学习些新技术,但是同时我认为最好的学习,应该是来自于实践,所以除了大量做项目,对刚学的技术最好的帮助就是分享,把别人给教会,而这也是一种能力的体现。所以我对分享并不是很排斥,反而有种强烈的喜欢。
而且分享还能打破封闭,对个人能力有很大的加成作用,不过难就难在跨出第一步,我刚开始分享也是有点慌,但等到第二场就开始驾轻就熟了,真的鼓励大家要不断的去尝试,不要重复自己,要敢于突破自己。
Web Components 这个技术是我在 「TS 高级语法」主题分享前给团队小伙伴的一个开胃小菜。
以下正文:
前端组件化
无论你用什么流行框架去写前端,本质上你都是在使用前端三剑客即: HTML、CSS 和 JavaScript。那这三剑客在自己的领域组件化/模块化
做的怎么样了呢?
- 对于 CSS,我们有
@impot
。 - 对于 JS 现在也有模块化方案。
那么对于 HTML 呢?我们知道样式和脚本都是集成到 HTML 中,所以所以单独的去做 HTML 模块化,没有任何意义。
既然如此,我们看看 HTML 在编程过程中遇到了什么问题。
- 因为 CSS 样式作用在全局,就会造成样式覆盖。
- 因为在页面中只有一个 DOM,任何地方都可以直接读取和修改 DOM。
可以看到我们的痛点就是解决 CSS 和 DOM 这两个阻碍组件化的因素,于是 Web Components 孕育而生。
Web Components
Web Components 由三项主要技术组成:
- Custom elements(自定义元素)。
- Shadow DOM(影子 DOM)。
- HTML templates(HTML模板)。
Web Components 整体知识点不多,内容也不复杂,我认为核心就是 Shadow DOM(影子 DOM),为什么我这么认为呢?看下 Shadow DOM 的作用你就明白了:
- 影子 DOM 中的元素对于整个网页是不可见的;
- 影子 DOM 的 CSS 不会影响到整个网页的 CSSOM,影子 DOM 内部的 CSS 只对内部的元素起作用。
看完,你发没发现它刚好解决了,我们开头前端组件遇到的问题,所以 Shadow DOM 才是 Web Components 的核心。
自定义元素(Custom elements)
如何自定义元素或叫如何自定义标签
自定义元素就像 Vue 和 React 中的类组件,首先我们需要使用 ES2015 语法来定义一个类,接着,使用浏览器原生的 customElements.define() 方法,告诉浏览器我要注册一个元素/标签 user-text
,(自定义元素的名称必须包含连词线,用与区别原生的 HTML 元素,就像 React 的自定义组件名使用时必须大写一样)。
class UserText extends HTMLElement {
constructor() {
super();
}
}
上面代码中,UserText 是自定义元素的类,这个类继承了 HTMLElement 父类。
我们现在把 user-text
作为标签使用,放到页面上去:
Document
我们看到页面成功渲染:
组件会有生命周期,所以这个类还有些方法:
- connectedCallback:当 custom element 首次被插入文档 DOM 时,被调用,俗称组件上树。
- disconnectedCallback:当 custom element 从文档 DOM 中删除时,被调用,俗称组件下树或组件消亡。
- adoptedCallback:当 custom element 被移动到新的文档时,被调用,这个 API 常和 document.adoptNode 配合使用。
- attributeChangedCallback: 当 custom element 增加、删除、修改自身属性时,被调用,俗称组件更新。
模板 (Templates)
页面上的元素最终是要给用户呈现内容,在自定义组件里,我们通过字符串的方式来接受要展现给用户的内容,这种方式非常不利于组织我们的 HTML,我们需要一个写 HTML 的地方,这个技术就是模板 (Templates),非常像 Vue 的模版渲染,如果你熟悉 Vue ,完全可以无障碍切换。
我们随便来弄点数据组织下代码,在浏览器展示给用户:
Document
你好,我是模版!
我们看到页面成功渲染:
如果,自定义元素需要动态传值给我们的自定义组件,可以使用插槽 slot,语法基本同 Vue,但是此时还无法演示,因为 slot 标签对标准的 DOM(更专业点叫 light DOM)无效,只对 shadow DOM 是有效的,看下使用示例。
Document
你好,我是模版!
因为我是无效的,我也会默认展示
light DOM 环境下,slot 标签没用
看下页面加载显示:
除了,slot 无法使用,我们还观察到 template 元素及其内容不会在 DOM 中呈现,必须通过 JS 的方式去访问、style 标签内的样式是作用到全局的、template 里面的 DOM 也可以被全局访问。
影子 DOM(shadow DOM)
影子 DOM 是 Web Components 核心中的核心,可以一举解决我们前面提到的,CSS 和 DOM 作用全局的问题。
看下使用示例:
Document
你好,我是模版!
因为我是无效的,我也会默认展示
light DOM 环境下,slot 标签没用
测试 shadow DOM 样式不作用全局
现在完成了,组件的样式应该与代码封装在一起,只对自定义元素生效,不影响外部的全局样式、DOM 默认与外部 DOM 隔离,内部任何代码都无法影响外部,同时 slot 也生效了,看下页面加载显示:
影子 DOM 的 mode 参数除了有 open,之外还有 closed,两者的区别在于此影子 DOM 是否能被访问外界访问,即是否能通过 JS 获取影子 DOM 读取 影子 DOM 里面的内容。
style 穿越 影子 DOM
任何项目为了统一风格,肯定需要有公共样式,而且为了方面是统一引入的,这就涉及到外部样式影响到内部样式,那怎么突破影子 DOM 呢?
CSS 变量
可以使用 CSS 变量来穿透 DOM:
CSS 变量样式穿透
按钮
页面展示效果图:
::part 伪元素
::part 伪元素的用法有点像具名插槽 slot。
::part 样式穿透
按钮
HTML 原生组件支持 Web Components
我们知道 HTML5 有很多的原生组件,例如:input,video,textarea,select,audio
等。
如果你审查元素会发现,这个组件并不是纯正的原生组件,而是基于 Web Components 来封装的。
如果你审查元素没有显示影子 DOM,请打开控制台,同时检查浏览器设置 Settings -> Preferences -> Elements
中把 Show user agent shadow DOM
打上勾。
落地应用有哪些?
首先,github 网址是完全基于 Web Components 来开发的,其次 Vue 和 小程序 也是基于 Web Components 来做组件化的,而且 Web Components 作为最底层的技术完全可配合 Vue 和 React 等框架,直接使用的。
光学不练那不是假把式吗,我来给大家整个 demo,自定义一个对话框,这个对话框只满足最基本的使用需求,先看下最终的成品。
源代码,可能比较难得两个思路:
- 数据更新,采用的是类的 get 和 set
- 关闭的回调事件,用的是自定义事件
自定义弹框
-
Let's have some different text!
Some contents Some contents......
Some contents Some contents......
Some contents Some contents......
Let's have some different text!
Some contents Some contents......
Some contents Some contents......
Some contents Some contents......
Let's have some different text!
Some contents Some contents......
Some contents Some contents......
Some contents Some contents......
Hello world
组件库
当我们谈到在项目中如何应用,我们首先需要两个东西,选个 UI 组件库,同时有比较好的工具来操作这个 UI 库,我提供两个给你参考。
- https://xy-ui.codelabo.cn/docs/#/
- https://lit-element.polymer-project.org/
参考
- An Introduction to Web Components
- MDN - Web_Components
- Web Components 入门实例教程