将来的组件化标准 —— 浅尝Web Components

原文地址css

前言

Web Components涉及到的内容仍是不少的,每一块都有不少东西能够讲,国外的好多大佬已经产出了好多优秀的文章。 本文照常只是简单了解大体内容而不进入深究,了解且会用便可,浅尝辄止。html

简介

Web Components自己不是一个规范,而是由W3C提出的另外4个规范的合集。这四个规范是:前端

下面咱们蜻蜓点水,简单了解一个这四个东西。vue

HTML Template

以前的页面开发常常的一个作法是把模板放在一个script标签或者隐藏的div中,用的时候经过innerHTML取出,塞进数据, 而后放回页面显示。如今咱们能够经过<template>标签存放了。就像这样:html5

<template id="mytemplate">
	<img src="" alt="great image">
  	<div class="comment"></div>
</template>
复制代码

特性检测

要特性检测 <template>,能够建立一个 template 元素并检查它是否拥有 content 属性:git

function supportsTemplate() {
	return 'content' in document.createElement('template');
}

if (supportsTemplate()) {
  	// 检测经过!
} else {
  	// 使用旧的模板技术或库。
}
复制代码

激活模板

激活模板,即渲染出模板里面的内容。激活模板最简单的方法就是使用 document.importNode() 对模板的 .content 进行深拷贝。 .content 为只读属性,关联一个包含模板内容的 DocumentFragment。github

var t = document.querySelector('#mytemplate');
// 在运行时填充 src。
t.content.querySelector('img').src = 'logo.png';

var clone = document.importNode(t.content, true);
document.body.appendChild(clone);
复制代码

特色

用 <template> 来包裹内容为咱们提供了几个重要属性:web

  • 它的内容在激活以前一直处于惰性状态。本质上,这些标记就是隐藏的 DOM,它们不会被渲染。ajax

  • 处于模板中的内容不会有反作用。脚本不会运行,图片不会加载,音频不会播放,...直到模板被使用。chrome

  • 内容不在文档中。在主页面使用 document.getElementById() 或 querySelector() 不会返回模板的子节点。

  • 模板可以被放置在任何位置,包括 <head>,<body>,或 <frameset>,而且任何可以出如今以上元素中的内容均可以放到模板中。 注意,"任何位置"意味着 <template> 可以安全的出如今 HTML 解析器不容许出现的位置... 几乎能够做为任何内容模型的子节点, 它也能够做为 <table> 或 <select> 的子元素。

推荐阅读

HTML Imports

以前在页面引入另外一个页面或片断每每是经过iframe或者ajax异步加载,而如今咱们能够这样作:

在head中引入

<head>
	<link rel="import" href="/path/to/imports/stuff.html">
</head>
复制代码

js中获取

var content = document.querySelector('link[rel="import"]').import;
复制代码

特性检测

要检测浏览器是否支持导入,可验证 <link> 元素上是否存在 import:

function supportsImports() {
	return 'import' in document.createElement('link');
}

if (supportsImports()) {
  	// 支持导入
} else {
  	// 使用其余方法加载文件
}
复制代码

推荐阅读

Shadow DOM

首先须要设置一下:打开开发者工具,f1打开设置(或右上角三个点),而后勾上Show user agent shadow DOM ——

而后再看下,video标签是这样的 ——

甚至一个普通的input ——

以前被隐藏掉的DOM部分就是shadow DOM。顾名思义,它是其宿主元素的影子,一般用来封装组件的内部结构。

因此像video、audio甚至input都是用简单的元素封装的组件。

这让我想到,咱们是否是能够经过修改元素里面的shadow DOM的样式来改变该元素的样式呢? 答案是 —— 是的,但也不彻底是...

从上图audio标签的结构和浏览器默认样式能够看到,咱们能够像这样修改对应的样式:

audio::-webkit-media-controls {
	...
}
复制代码

就像经过::-webkit-scrollbar改造浏览的滚动条样式那样,

因而,默认的audio样式(新版chrome)——

small

通过改造后,能够变成这样——

small

然而并非全部样式均可以这样覆盖改造,像pseudo="-internal-media-controls-loading-panel"这样以"-internal-"开头的是不能够的。 因此这个作法仍是有很大局限性的。

这是我试出来的,并没发现相关标准或依据...😓

demo地址

这种作法自认为只适合拿来玩玩而已,不适合投入到项目开发中去。一来是由于其局限性太大,二来谁知道啥时候浏览器升级,这些标签的内部结构就又变化了呢, 最重要的是shadow DOM是为web Components而生的,与Custom Elements一块儿是web Components的重要组成部分,并不是用于此“旁门左道”😆。

推荐阅读

Custom Elements

自定义元素,首先有个硬性规定,自定义元素的命名中必需要有中划线“-”,不然即是未知元素了。

自定义元素分为两种 ——

自特性主自定义元素(Autonomous custom elements)

不具有任何已有元素的,其样式和行为彻底自定义,如咱们要定义一个这样的元素:

<flag-icon country="cn"></flag-icon>
复制代码

经过给属性country赋值来显示对应的国旗。

js的基本结构是这样的

class FlagIcon extends HTMLElement {
  	constructor() {
    	super();
    	this._countryCode = null;
  	}

  	static get observedAttributes() { return ["country"]; }

  	attributeChangedCallback(name, oldValue, newValue) {
	    // name will always be "country" due to observedAttributes
	    this._countryCode = newValue;
	    this._updateRendering();
  	}

  	connectedCallback() {
    	this._updateRendering();
  	}

  	get country() {
    	return this._countryCode;
  	}

  	set country(v) {
    	this.setAttribute("country", v);
  	}

  	_updateRendering() {
	    //...
  	}
}

//全局注册该元素
customElements.define("flag-icon", FlagIcon);
复制代码

注册后,也经过js建立该元素

const flagIcon = document.createElement("flag-icon");
flagIcon.country = "cn";
document.body.appendChild(flagIcon);
复制代码

自定义内置元素(Customized built-in elements)

继承自已有元素,拥有已有元素的全部特性。

好比咱们自定义一个按钮,集成普通按钮全部的特性,可是当点击的时候会有一个动效,就能够这么作 ——

class PlasticButton extends HTMLButtonElement {
  	constructor() {
    	super();

    	this.addEventListener("click", () => {
      		// 动效逻辑
    	});
  	}
}
复制代码

不一样的是,注册时要加上一个参数

customElements.define("plastic-button", PlasticButton, { extends: "button" });
复制代码

使用时也稍有不一样

<button is="plastic-button">点我!</button>
复制代码

经过js定义元素,则是这样

const plasticButton = document.createElement("button", { is: "plastic-button" });
plasticButton.textContent = "点我!";
document.body.appendChild(flagIcon);
复制代码

生命周期

用过Vue、React等框架的同窗对生命周期应该不陌生。一样,自定义元素有4个生命周期:

connectedCallback

元素首次被插入文档DOM时触发

disconnectedCallback

元素从文档DOM中删除时触发

adoptedCallback

元素被移动到新的文档时触发

attributeChangedCallback

元素增长、删除、修改自身属性时触发

推荐阅读

来一个demo

评分组件相信你们都司空见惯了。照葫芦画瓢,我用原生js写了一个Web Components 版的,简单实现了该组件的基本功能。

demo截图:

demo地址

推荐阅读

总结

Web Components 为前端组件化提供了解决方案,但用惯了Vue这样的框架,仍是会发现Web Components 的问题, 好比

  • 浏览器的支持
  • 对样式局部做用域的处理,每每js中包着一堆的CSS样式,略显臃肿
  • 父子、兄弟组件的通讯问题
  • 属性都是字符串,须要额外的代码作转换和兼容
  • 没有数据驱动,基本全是DOM操做

我的愚见,望大佬指点!🙏

相关文章
相关标签/搜索