Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >怎样开发可重用组件并发布到NPM [每日前端夜话0x24]

怎样开发可重用组件并发布到NPM [每日前端夜话0x24]

作者头像
疯狂的技术宅
发布于 2019-03-27 02:50:47
发布于 2019-03-27 02:50:47
1.2K00
代码可运行
举报
文章被收录于专栏:京程一灯京程一灯
运行总次数:0
代码可运行

每日前端夜话0x24

每日前端夜话,陪你聊前端。

每天晚上18:00准时推送。

正文共:7212 字

预计阅读时间: 18 分钟

翻译:疯狂的技术宅 原文:https://www.smashingmagazine.com/2018/07/reusable-components-custom-elements-shadow-dom-npm/

摘要:本文着眼于使用具有内置功能和样式的组件来扩充HTML。 我们还将学习如何通过 NPM 使这些自定义元素在项目中得到重用。


即便是最简单的组件,人力成本也可能很高UX 团队进行要可用性测试。 涉及到的利益相关者必须对设计签字确认。

之后是开发人员进行 AB 测试,可访问性审计,单元测试和跨浏览器检查。 一旦解决了这个问题,你就不想再次重复这项工作了。 通过构建可重用的组件库(而不是从头开始构建所有内容),我们就可以不断复用过去的工作,避免重新审视已经解决的设计和开发过程。

构建组件库对于像Google这样的公司尤为重要,他们拥有很多具有相同品牌的网站。 通过把 UI 编码为可组合小部件,这些大公司既可以减少开发时间,又可以实现跨项目的可视化和用户交互设计的一致性。在过去几年中,人们对样式指南和模式库的兴趣不断增加。由于开发人员和设计师一般都分布在多个团队中,所以大公司需要寻求实现一致性的方法,比如提供简单的颜色样本。不过对于我们来说,可以比他们做得更好。 我们需要的是易于分发的代码

共享和重用代码

手动复制和粘贴代码很容易。但是把代码保持在最新版是维护上的噩梦。所以许多开发者依赖包管理器来跨项目重用代码。 尽管名字是 Node Package Manager, 但是它已成为前端包管理的独一无二的平台。 目前在 NPM 上注册的包超过700,000个,每月下载数十亿次。 含有 package.json 文件的任何文件夹都可以作为可共享包上传到NPM。 虽然NPM主要与JavaScript相关联,但包中也可以包含 CSS 和标记。 NPM使重用变得很容易,这对更新代码尤为重要:你无需在各种地方修改代码,所做的是只需在包中更新代码即可。

标记存在的问题

使用 import 语句可以对Sass和Javascript 进行轻松移植。 模板语言赋予了 HTML 相同的能力 —— 模板能以局部形式导入到 HTML 的其他片段。 比如你可以只需为页脚编写一次标记,然后将其包含在其他模板中即可。 另一种方法是复制并粘贴标记,并只对样式和 javascript 使用NPM。

这是英国“金融时报”在 Origami 组件库【http://origami.ft.com/】中用到的方法。Alice Bartlett在她的演讲中总结道:“你不能让它更像是 Bootstrap 吗?”【https://www.youtube.com/watch?v=LAVNOQroZYA】,“并没有什么好办法能让人们在他们的项目中包含模板”。 Ian Feather谈到他在 Lonely Planet 维护组件库的经历,重申了这种方法存在的问题【https://www.ianfeather.co.uk/a-maintainable-style-guide/】:

“一旦复制了这些代码,他们基本上就会削减一个需要无限期维护的版本。当复制工作组件的标记时,它具有到该点的CSS快照的隐式链接。 如果你随后更新模板或重构CSS,则需要更新分散在你网站周围的所有模板的版本。“

解决方案:WEB组件

Web组件通过在 JavaScript 中定义标记来解决这个问题。 组件的作者可以自由地修改标记、CSS 和 Javascript。 组件的使用者可以在这些升级中受益,无需手动修改项目代码。 只需要通过在终端的敲出简短的 npm update 命令,就可以在项目范围内更新到最新版本。当然前提是组件的名称及其 API 需要保持一致。

安装Web组件就像在终端中键入 npm install component-name 一样简单。 Javascript 可以包含在 import 语句中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1<script type="module">
2import './node_modules/component-name/index.js';
3</script>

在CodePen上的代码演示:https://codepen.io/cssgrid/pen/KemvbM

在前端开发中,以组件为中心的方法已经变得无处不在,Facebook 的 React 框架就使用了这种方法。考虑到在现代前端开发工作中框架的普遍性,许多公司已经在用他们选择的框架构建了组件库。这些组件只能在该特定框架内重用。

IBM Carbon Design System的一个组件。 仅能用于 React 应用。其他在 React 中构建的组件库的主要案例包括Atlassian 的 Atlaskit 【http://atlaskit.atlassian.com/packages】 和 Shopify 的 Polaris【https://polaris.shopify.com/components/get-started/】

对规模较大的公司来说,很少有统一的前端,从一个框架转到另一个框架的重新布局并不罕见。各种框架你方唱罢我登场。 为了在项目中实现最大程度的潜在重用,我们需要与框架无关的组件。

通过在npmjs.com对组件的搜索结果揭示了一个支离破碎的Javascript生态系统

随着时间的推移,框架也在不断变化

“多年来我使用 Dojo、Mootools、Prototype、jQuery、Backbone、Thorax 和 React 构建了 Web 应用……我希望能把我开发的 Dojo 组件用到现在的 React 应用中。“ —— 谷歌工程总监Dion Almaer

当我们谈论Web组件时,我们讨论的是自定义元素与 shadow DOM 的组合。 自定义元素和 shadow DOM 是W3C DOM 规范和 WHATWG DOM 标准的一部分 —— 这意味着 Web 组件是 Web 标准的一部分。自定义元素和 shadow DOM 最终会实现跨浏览器支持。 通过使用原生 Web 平台的标准部分,我们确保自己的组件能够在前端重组和不断重构的快速变化周期中生存下来。 Web组件可以与任何一种模板语言和前端框架一起使用 —— 它们是真正交叉兼容和可互操作的。 从 Wordpress 博客到单页应用程序,可以在任何场合下使用。

Rob Dodson的 Custom Elements Everywhere 项目【https://custom-elements-everywhere.com/】记录了 Web 组件与各种客户端 Javascript 框架的互操作性。 这里面 React 出现的异常值,希望能在 React 17 中解决

制作Web组件

定义一个自定义元素

生成 made-up-tag 标记并使其内容显示在页面上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1<made-up-tag>Hello World!</made-up-tag>

HTML 被设计为能够容错。即使不是有效的HTML元素,它的内容也会被呈现。 并没有一个很好的理由这样做 —— 偏离标准化标签在传统上是很差劲的做法。 但是通过用自定义元素 API 定义新的标记,我们就可以用具有内置功能的可重用元素来扩充HTML。 创建自定义元素很像在 React 中创建一个组件 —— 但在这里是扩展了 HTMLElement

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1class ExpandableBox extends HTMLElement {
2      constructor() {
3        super()
4      }
5    }

构造函数中的第一个语句必须是对 super() 的无参数调用。构造函数应该用于设置初始状态和默认值,以及设置事件侦听器。 需要使用其 HTML 标记的名称和对应的类的元素定义新的自定义元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1customElements.define('expandable-box', ExpandableBox)

把类名大写是一种惯例。 HTML 标记的语法不仅仅是一种约定,如果浏览器想要实现一个新的HTML元素,并且想把它称为可扩展框怎么办?为了防止命名冲突,不是最新标准的 HTML 标记要包含破折号。 所以自定义元素的名称也 必须 包含破折号。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1customElements.define('whatever', Whatever) // 无效
2customElements.define('what-ever', Whatever) // 有效
定制元素生命周期

API 提供了四种自定义元素响应 —— 可以在类中定义函数,这些函数会自动调用来响应自定义元素生命周期中的某些事件。

当自定义元素添加到 DOM 时会执行 connectedCallback

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1connectedCallback() {
2    console.log("custom element is on the page!")
3}

这包括用 Javascript 添加元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1document.body.appendChild(document.createElement("expandable-box")) // "custom element is on the page"

以及简单地在页面中包含带有 HTML 标记的元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1<expandable-box></expandable-box> // "custom element is on the page"
2

所有涉及到获取资源或渲染的工作都应该在这里。

从 DOM 中删除自定义元素时,将运行 disconnectedCallback

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1disconnectedCallback() {
2    console.log("element has been removed")
3}
4document.querySelector("expandable-box").remove() //"element has been removed"

当自定义元素被采用到新文档中时,将会运行 adoptedCallback 。 你可能不需要太关心这个问题。

在添加、更改或删除属性时运行 attributeChangedCallback 。 它可以用于监听标准化本机属性(如 disabledsrc )的更改,以及我们定义的任何自定义属性。 这是自定义元素最强大的功能之一,因为它可以创建用户友好的 API。

定制元素属性

因为有很多 HTML 属性,所以当任何属性发生变化时,浏览器都不会浪费时间去调用我们的 attributeChangedCallback ,因此需要提供一个我们想要监听的属性更改列表。对于这个例子,我们只对一个感兴趣。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1static get observedAttributes() {
2            return ['expanded']
3        }

所以现在 attributeChangedCallback 只会在我们更改自定义元素上expanded属性的值时被调用,因为它是我们列出的唯一属性。

HTML 属性可以有相应的值(例如 href,src,alt,value 等),而其他值可以是true或false (例如 disabled, selected, required)。 对于具有相应值的属性,我们将在自定义元素的类定义中包含以下内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1get yourCustomAttributeName() {
2  return this.getAttribute('yourCustomAttributeName');
3}
4set yourCustomAttributeName(newValue) {
5  this.setAttribute('yourCustomAttributeName', newValue);
6}

对于例子中的元素,其属性为 true 或 false,因此定义 getter 和 setter 会有所不同。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1get expanded() {
 2  return this.hasAttribute('expanded')
 3}
 4
 5// setAttribute的第二个参数是必需的,所以我们将用一个空字符串填充
 6set expanded(val) {
 7  if (val) {
 8    this.setAttribute('expanded', '');
 9  }
10  else {
11    this.removeAttribute('expanded')
12  }
13}

既然已经处理了样板文件,我们可以使用 attributeChangedCallback

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1attributeChangedCallback(name, oldval, newval) {
2  console.log(`the ${name} attribute has changed from ${oldval} to ${newval}!!`);
3  // 每次属性被更改时执行某些操作
4}

配置 Javascript 组件会涉及将参数传递给 init 函数。 通过使用 attributeChangedCallback ,可以创建一个可以使用标记配置的自定义元素。

Shadow DOM 和自定义元素可以单独使用,你可以找到对自己有用的自定义元素。 与 shadow DOM 不同,它们可以是 Polyfill。 不过它们配合得很好。

使用SHADOW DOM附加标记和样式

到目前为止,我们已经处理了自定义元素的行为。 但是关于标记和样式,我们的自定义元素相当于空的无样式 <span> 。 要将HTML和CSS封装为组件的一部分,还需要附加一个shadow DOM。 最好在构造函数中执行此操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1class FancyComponent extends HTMLElement {
2        constructor() {
3            super()
4            var shadowRoot = this.attachShadow({mode: 'open'})
5            shadowRoot.innerHTML = `<h2>hello world!</h2>`
6            }

不要为理解模式的含义担心——你必须包含它的样板,但你几乎总是想要 open。 这个简单的例子组件将只呈现文本“hello world”。 与大多数其他 HTML 元素一样,自定义元素可以包含子元素 —— 但默认情况下不是。 到目前为止,前面的自定义元素还不能将任何子元素渲染到屏幕上。 要显示标记之间的内容,还需要用到 slot 元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1shadowRoot.innerHTML = `
2<h2>hello world!</h2>
3<slot></slot>
4`

我们可以用样式标记将 CSS 应用于组件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1shadowRoot.innerHTML = 
2`<style>
3p {
4color: red;
5}
6</style>
7<h2>hello world!</h2>
8<slot>some default content</slot>`

这些样式仅适用于组件,因此我们可以自由地使用元素选择器,而不会影响页面的任何其他内容。 这就把编写 CSS 的过程变得非常简单,使 BEM 这样的命名约定变得不必要。

通过 NPM 发布组件

NPM 包通过命令行进行发布。 打开一个终端窗口并切换到你想要变成可重用包的目录中,然后在终端中键入以下命令:

  1. 如果你的项目还没有 package.json【https://docs.npmjs.com/files/package.json】, npm init 将会引导你创建一个。
  2. npm adduser 把你的机器链接到你的 NPM 帐户。 如果你还没有注册,它将为你创建一个新的账号。
  3. npm publish

如果一切顺利的话,在 NPM 列表中会出现你的组件,可以在你自己的项目中安装和使用 —— 并与全世界共享。

Web组件API并不完美。自定义元素目前还无法在表单提交中包含数据【https://github.com/w3c/webcomponents/issues/187】。 渐进式增强并不是很好,对可访问性的处理并不怎么容易【https://github.com/WICG/aom/blob/gh-pages/explainer.md#use-case-1-setting-non-reflected-default-accessibility-properties-for-web-components】。

尽管最初在 2011 年宣布,但浏览器还没有普遍支持。 Firefox 将在今年(2018)晚些时候提供支持。 尽管如此,一些备受瞩目的网站(如 Youtube )已经在使用它们。 尽管目前还存在缺点,但对于普遍可共享的组件而言,它们是唯一的选择,并且在未来它们提供的令人兴奋的新功能非常值得期待【https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Template-Instantiation.md】。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-02-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Web Components 详解
我们在业务中经常会自行定义ui 控件,这确实能达到复用的目的,但是它不是常常有效,但是有时它也会表现的糟糕,比如样式错乱。
前端知知
2022/09/29
1.2K0
Web Components 详解
如何实现一个Web Component组件
Web Component 是一套不同的用于构建可重用并封装化的组件化技术,允许你创建可重用的定制元素(它们的功能封装在你的代码之外)并且在你的 web 应用中使用它们。它是由一组标准规范组成的。其中最重要的规范包括 Custom Elements、Shadow DOM、HTML Templates 和 HTML Imports。
用户6297767
2023/12/14
3950
如何实现一个Web Component组件
Web Components 上手指南
现在的前端开发基本离不开 React、Vue 这两个框架的支撑,而这两个框架下面又衍生出了许多的自定义组件库:
童欧巴
2021/03/18
9980
Web Components 上手指南
深入解剖前端,你不知道的Web 组件标准
组件化使得复杂的前端结构变得清晰,各个部分独立起来,高内聚低耦合,使得维护成本大大降低。
一墨编程学习
2018/11/22
1.1K0
Web Components:自定义元素与Shadow DOM的实践
Web Components是现代Web开发中用于创建可重用和封装的自定义HTML元素的一组技术。它包括Custom Elements、Shadow DOM、HTML Templates和Slots。
天涯学馆
2024/05/17
2670
尤大 3 天前发在 GitHub 上的 vue-lit 是啥?
尤大北京时间 9月18日 下午的时候发了一个微博,人狠话不多。看到这个表情,大家都知道有大事要发生。果然,在写这篇文章的时候,上 GitHub 上看了一眼,刚好碰上发布:
lucifer210
2020/09/24
9590
尤大 3 天前发在 GitHub 上的 vue-lit 是啥?
秒懂 Web Component
最近不是写了一篇关于京东微前端框架的文章嘛 《初探 MicroApp,一个极致简洁的微前端框架》,里面提到了一个叫 Web Components 的东西。虽然对它早有耳闻,但是一直也没怎么仔细看过,所以就深入了解了一下,今天给大家做个简单分享 :)
写代码的海怪
2022/03/29
7450
秒懂 Web Component
试试原生 Web Component: 比你想象的容易
<template>是一个HTML元素,它允许我们创建一个模板——web组件的HTML结构。模板不必是一大块代码。它可以很简单:
前端修罗场
2022/07/29
7960
试试原生 Web Component: 比你想象的容易
如何基于 WebComponents 封装 UI 组件库
作为一名前端攻城狮,相信大家也都在关注着前端的一些新技术,近些年来前端组件化开发已为常态,我们经常把重用性高的模块抽离成一个个的组件,来达到复用的目的,这样减少了我们的维护成本,提高了开发的效率。但是都有一个缺点离不开框架本身,因为我们浏览器本身解析不了那些组件。那么有没有一种技术也可以达到这种效果呢?答案就是今天的主角 Web Components。
政采云前端团队
2022/08/30
1.5K0
如何基于 WebComponents 封装 UI 组件库
每天 React, Vue, 你知道如何原生实现 WebComponent吗?
原文地址:https://juejin.cn/post/7034796986889043999
coder_koala
2021/12/01
7950
深入理解Shadow DOM v1[每日前端夜话0x63]
shadow DOM不是超级英雄电影中的恶棍,也不是DOM的黑暗面。 shadow DOM只是一种解决文档对象模型(或简称DOM)中缺少的树封装方法。
疯狂的技术宅
2019/05/15
1.2K0
web components的一些知识点
上篇文章大致说了一下用web-components重新封装UI库的思路,并附了一个demo,代码写的垃圾,无所谓了,重要的是有思路才行。这次大致对web components这个东西,简单的做下介绍。
terrence386
2022/07/14
4920
Web Components 的使用,从入门到基础
Web Components[以下简称"WC"],使用自定义元素(custom elements)来代替div,故能使用div的得房就能使用它。因此,使用WC,只需要在HTML中引入js文件即可。它不并不像目前主流的组件框架,需要外部支撑。例如,如果你要使用React组件,那你大概率的情况下要使用ReactJS。
前端修罗场
2023/10/07
4060
Web Components 的使用,从入门到基础
Web Components 笔记
关键字:ES2015类的自定义元素写法、全局声明自定义元素、shadowroot,生命周期事件
申君健
2020/03/27
4420
原生javascript组件开发之Web Component实战
作为一名前端工程师,我们每天都在和组件打交道,我们也许基于react/vue使用过很多第三方组件库,比如ant design,elementUI,iView等,或者基于它们进行过组件的二次开发,比如业务组件,UI组件等,亦或者觉得团队能力很强,可以不依赖第三方而独立开发属于自己的组件库。无论何种形式,组件开发已然成为我们工作中的必备技能,为了更好的复用性和可维护性,组件化开发是必然选择,也正是因为组件化开发越来越重要,几年前web标准推出了Web Component这一概念,意在解决html原生标记语言复用性的问题。
徐小夕
2020/06/24
2K0
原生javascript组件开发之Web Component实战
Web Components从技术解析到生态应用个人心得指北
Web Components 是一种使用封装的、可重用的 HTML 标签、样式和行为来创建自定义元素的 Web 技术。
周陆军博客
2024/01/18
7400
打造一套安全的UI组件库!
现在再开发一套UI框架似乎已经错过了最佳创业时期,毕竟网上优秀的框架一大堆,轻量级的,重量级的,有依赖的,无依赖的,拿来即用的,需要配置的,应有尽有。但是老衲我找遍整个外网发现唯独没有利用Web Component标准库实现的前端框架,要知道组件化可是Vue,React和Angular的招牌卖点之一,如今Web Component标准库可以完美提供原生的组件化开发模式,这直接意味着前端框架市场仍然有风口,而我选择使用Web组件标准库来开发UI框架的最大卖点是:安全。
Jean
2019/08/28
1.3K0
打造一套安全的UI组件库!
【Web技术】400- 浅谈Shadow DOM
你在实际的开发中很可能遇到过这样的需求:实现一个可以拖拽的滑块,以实现范围选择、音量控制等需求。
pingan8787
2019/11/05
5780
【Web技术】264- Web Component可以取代你的前端框架吗?
还记得当document.querySelector最开始被广泛的被浏览器支持并且结束了无处不在的JQuery。这最终给我们提供了一个原生的方法,虽然JQuery已经提供了很久。我觉得这同样将会发生在像Angular和React这的前端框架身上。
pingan8787
2019/07/25
2.6K0
【总结】- 从 0 到 1 上手 Web Components 业务组件库开发
组件化是前端发展的一个重要方向,它一方面提高开发效率,另一方面降低维护成本。主流的 Vue.js、React 及其延伸的 Ant Design、uniapp、Taro 等都是组件框架。Web Components 是一组 Web 原生 API 的总称,允许我们创建可重用的自定义组件,并在我们 Web 应用中像使用原生 HTML 标签一样使用。目前已经很多前端框架/库支持 Web Components。
pingan8787
2021/12/29
2K1
【总结】- 从 0 到 1 上手 Web Components 业务组件库开发
推荐阅读
相关推荐
Web Components 详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验