为了账号安全,请及时绑定邮箱和手机立即绑定
慕课专栏

目录

索引目录

Vue3核心源码详解38讲

限时优惠 ¥ 48.00

原价 ¥ 68.00

12月18日后恢复原价

限时优惠
立即订阅
03 现代 Web 应用开发的特征二:组件化
更新时间:2020-11-17 08:54:20
人不可有傲气,但不可无傲骨。——徐悲鸿

在前文介绍 Vue 的时候,提到过一些组件化的好处:能让 web 前端代码也实现“高内聚 低耦合”,使得前端开发的过程变成搭积木的过程。

web 领域的前辈们在组件化的概念落实中进行过非常多的尝试。例如 ext.js 之类的框架在组件化方面做得非常深入,但因为种种原因,受众有限,最终没有大规模地流行起来。

jQuery 插件体系也算是一个比较庞大的组件化生态系统了,但 jQuery 对插件的支持并没有从组件化方面去着手考虑,只是因为插件需要被复用,因此被强制将所有逻辑打包到同一个插件中,被迫变成了一个“组件”,事实上它并不太满足开发者对组件真正的要求。

组件的要求

一个组件要实现“高内聚 低耦合”,同时还要能被方便地复用,大概需要满足以下几个条件:

组件内方便互相引用

当开发者需要将一段或者一堆代码抽象成组件时,说明这段代码已经具备了完整的功能(否则这个组件无法使用),也说明它具备了一定的复杂度(否则不需要抽象成组件)。

在一个组件的内部,一定会有彼此交叉引用、调用的情况。针对前端代码而言,还可能存在结构、逻辑、样式互相依赖和引用的情况(例如通过某一些状态的变更修改页面的某些样式)。因此,组件内的代码必须能非常方便地互相引用。

组件外部通过接口通信

在“高内聚 低耦合”的原则下,一个组件应该通过合理的规划,暴露出自己的公开接口(包括属性、方法、事件等),而不同组件之间的通讯应该只通过公开接口来完成。

这样的话,开发者就能真正掌握组件对外通信的方式,在此基础上合理地组织整个应用的结构。从而更好地完成应用的架构。

隐藏细节 避免干扰

在暴露公开接口、使用公开接口完成通信的前提下,组件的开发者可以获得一些额外的好处:

  1. 在不修改公开接口的情况下,放心地对内部逻辑进行迭代、重构。
  2. 清楚地理解组件的边界和通信逻辑,避免通信带来的调试负担。

因为组件之间只可以使用公开接口通信,因此在对内部逻辑进行迭代和重构的时候,不用担心没有公开的部分会被外部访问或引用,从而能随意修改实现细节。因为有测试用例的存在,整个修改和重构的过程只要能跑通测试用例,即可以说明它是和上一个版本兼容的,从而更放心地升级发布。

在调试的时候,因为非常清楚组件的边界和通信逻辑,因此诸如数据在哪里被修改的、触发了什么事件、和谁产生了通信之类的都非常清楚,从而能快速地界定问题出现在哪一部分的代码中,极大提高代码调试的效率。

文件组织方便

一个组件的代码应该是高度内聚的,即组件的所有代码应该在同一个地方或者非常邻近的地方。因为只有这样才方便组件的开发者进行开发维护,也方便组件的应用者来组织代码。

在传统的 web 应用开发过程中,喜欢强调“结构、表现、行为分离”,即将 HTML/DOM、CSS、JS 三部分的代码独立开来,甚至放在完全不同的目录中。但是一旦有了组件的概念,这种组织方式就不适用了。将同一组件的各部分代码分布在离得很远的地方,既不方便维护、也不方便使用和调试。

web components 组件方案

现代 web 应用开发已经形成了以组件为中心的代码组织方式,但在从无到有的探索过程中出现了非常多的实现方案。这里只介绍比较重要的 web components。

web components 是由浏览器原生支持的一套组件规范,它的发展和规范化已经历练 10 来年了。事实上,web components 并不是一个单一的规范,而是由一系列的规范共同组成:

  • custom elements(自定义元素)
  • shadow DOM(影子 DOM)
  • HTML templates(HTML 模板)

限于篇幅,这里不详细介绍各自的详细用法,只大概说明这三个规范的用途。

HTML templates

HTML templates 即 HTML 模板,顾名思义,它就是用来提供一些 HTML 的片段作为模板来使用的,看 MDN 上的例子:

<template id="my-paragraph">
    <p>My paragraph</p>
</template>

上面的代码不会展示在页面中,只能用 JavaScript 获取它的引用,然后添加到 DOM 中:

let template = document.getElementById('my-paragraph');
let templateContent = template.content;
document.body.appendChild(templateContent);

这个例子非常平淡无奇,但 HTML 模板真正神奇的地方其实是 slots(插槽)。熟悉 Vue 的开发者应该知道 Vue 是有 slots 这样的特性的,它可以帮助我们在隐藏子组件的细节的提前下,指定子组件中一部分内容。而这个 slots 的概念,正是来自于 HTML templates。

在某个自定义组件(my-paragraph)的 HTML templates 中定义 slots:

<p><slot name="my-text">My default text</slot></p>

使用 slots:

<my-paragraph>
    <ul slot="my-text">
        <li>Let's have some different text!</li>
        <li>In a list!</li>
    </ul>
</my-paragraph>

可以看到它和 Vue 的 slots 如出一辙。

Shadow DOM

Shadow DOM 的核心思想是将一部分的 DOM 结构封装起来,与主 DOM 树进行隔离,从而避免外部样式、脚本的干扰,从而提供组件内部封装的能力。

事实上在 Shadow DOM 的能力被浏览器实现以后,有大量原生 HTML 元素,在渲染的时候都是使用的 Shadow DOM。以<video>为例,我们在使用的时候只需要一个<video>元素(或者再加一个/一些<source>元素)即可,但这个组件在渲染的时候却有视频画面、全屏、播放/暂停、音量调节、进度条等界面元素。这些元素在内部实现的时候正是使用的 Shadow DOM。在调试工具中可以清楚地看到它的内部结构:

图片描述

而我们通过 JS 脚本并不能获取和操作这些内部元素,我们的 CSS 样式也不会影响这些内部元素的样式,这正说明了 Shadow DOM 具有实现组件内部封装、隔离外界干扰的能力。

如果我们将 Shadow DOM 的能力看作一个组件封装的能力,则 HTML templates 可以为它提供一部分父子组件复用通信的能力。此时,如果我们要将 Shadow DOM 作为组件单独拿出来用,还需要一个好用的引用能力(即,你要如何引入之前用 Shadow DOM 定义的组件),这个能力则可以由 custom elements 提供。

custom elements

custom elements 可以让我们拥有自定义 HTML 元素的能力。简单地说,你可以创建一个名为<popup-info>的元素,然后定义它的结构和行为。MDN 上就有一个这样的例子,自定义了一个弹框(PopUpInfo代码太长这里不贴了):

customElements.define('popup-info', PopUpInfo);

使用时只需要引入即可:

<popup-info img="img/alt.png" text="Your card validation code (CVC)
  is an extra security feature — it is the last 3 or 4 numbers on the
  back of your card.">

这个使用方法其实和 Vue 已经非常类似了。

综合起来看:

  • custom elements 提供了自定义 HTML 元素的能力,让我们很方便地引用自定义的 UI 界面元素
  • 在 custom elements 定义过程中,可以使用 Shadow DOM 封装内部逻辑、隔离外部干扰
  • html template 提供了一定的组件复用通信能力

这些能力加起来就能提供一个可用的组件方案。

但 web components 也有它的问题。

最突出的问题就是兼容性的问题。自 web components 的概念提出以来,相关的规范基本上一直处于频繁变动的状态,甚至连哪些规范属于 web components 都在不断变动。例如早期还有一个 scoped css 规范(这也是 Vue 中 scoped css 方案的来源),也属于 web components 的范围,但现在不这么提了。

因此在差不多长达十年的时间里,web components 几乎一直处于不稳定的状态,这导致了它一直无法被大规模地应用。

而即便今天 web components 能提供稳定的 API 了,它也不太可能再大规模地流行了。因为前面我们说的组件化的趋势,已经由框架和工具链完整地建立起来了。也即,在今天的 web 开发过程中,无论有没有 web components 的原生支持,都不影响开发者使用组件化的方式来架构应用。因此再回到使用原生 web components 来开发 web 应用的可能性已经不太大。何况有一些框架已经具备了编译到 web components 的能力。

因此,在未来很长一段时间内,框架的组件化方案都将成为 web 开发者采用的主要方案。

}
限时优惠 ¥ 48.00 ¥ 68.00

你正在阅读课程试读内容,订阅后解锁课程全部内容

千学不如一看,千看不如一练

手机
阅读

扫一扫 手机阅读

Vue3核心源码详解38讲
限时优惠 ¥ 48.00 ¥ 68.00

举报

0/150
提交
取消