hylerrix
Love the world!
——入门、实战与持续更新
@2018-09-16
@西安 Web 前端交流大会
freeCodeCamp 2018 Top Contributor,开源爱好者,参与、组织过多次开源技术社区活动,目前在滴滴进行前端岗位的实习。
Try to create “webcomponents-china” organization
* 本场分享定义的难度为初级——概念型。 * 本场分享希望达到的效果:Web Components 背景与概念过一遍,持续关注线上的更新。 * 本场分享参考了大量的资料。
零、进击的前端框架,加速前端组件化进程
0-1 前后端分离的进程
① 前后端分离,REST 架构发展
② 传统开发方式(单体架构):
build | 项目构建(webpack)相关代码 |
---|---|
config | 配置目录,包括端口号等。我们初学可以使用默认的。 |
node_modules | npm 加载的项目依赖模块 |
src | |
这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件: | |
assets: 放置一些图片,如logo等。 | |
components: 目录里面放了一个组件文件,可以不用。 | |
App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。 | |
main.js: 项目的核心文件。 | |
static | 静态资源目录,如图片、字体等。 |
test | 初始测试目录,可删除 |
.xxxx文件 | 这些是一些配置文件,包括语法配置,git配置等。 |
index.html | 首页入口文件,你可以添加一些 meta 信息或统计代码啥的。 |
package.json | 项目配置文件。 |
README.md | 项目的说明文档,markdown 格式 |
软件系统是整块应用,效率低、维护成本高、复杂度随业务增长呈指数级增长
③ 热插拔式化繁为简:
前端 -> 组件化
后端 -> 微服务
行业性实践
...微服务
0-2 前端组件化发展的几个阶段
1. 交互少的静态页面时期:公共 JS 模块公共 CSS 2. 早期动态页面时期:动态引入 * 由于静态页面不能在页面上存储数据,需要一种技术能把交互的动态数据展现起来。 * 于是出现了很多服务端技术,比如 ASP,JSP。这些技术的出现使得前端页面活起来了,用户可以根据自己的需求进行数据的交互。 * 此时页面逻辑逐步复杂,也被公用出来:比如公共的页面头(header)和尾(footer)以及数据库的连接(DatabaseConn.jsp)等。
0-2 前端组件化发展的几个阶段
3. 后端为主的 MVC 时期:Tag 标签 * 早期动态页面时期的业务逻辑都写在页面上,随着逻辑的增多,页面越来越复杂 * 以 servlet 为代表的 MVC 时代逐渐登上历史舞台,这时页面上的逻辑都被转入到 servlet 中,使得 View 层的表现更加简洁,也更加的易于阅读,从而达到了开发的分层。 * 随着 Struts 以及 Spring 的出现,MVC 的开发方式达到鼎盛时期,前端 View 层的展现也变得越来越简单,没有了复杂的业务逻辑,前端的组件化方式主要是 taglib 标签,比如 jsp 标签,Struts 标签等,把 HTML 代码和业务逻辑打包成一个标签,然后使用者直接放置在想要的地方,就可以了。 * 但这个时期,整个 WEB 应用的开发轻前端重后端,那些 taglib 标签也都是 JAVA 代码编写的。 4. 前端 Ajax 时期:JS 大行其道 * 服务端动态渲染消耗服务器性能,AJAX 的出现备受欢迎,服务端只用专注提供数据。 * 这时出现了 JQuery-UI, easy-UI,miniUI 以及大名鼎鼎的 ExtJS。 * 组件共用起来很复杂。
0-2 前端组件化发展的几个阶段
5. 前端 MV* 时期:自定义组件 * 想要修改这些(ExtJS,miniUI)JS 框架中的组件是非常困难的,因此开发者希望能够很容易的自定义一些组件,而且可以让开发者将已经存在的组件进行封装。 * 这时 npm 以及 bower 这些包管理库也出现,开发者可以很容易的将自己开发的组件 publish 到这些库中,在使用时只要把他们下载下来(比如 npm install)就可以直接使用。 * Backbone、Angular、React、Vue 等框架逐步成为潮流。 6. 以上的组件化基本以 HTML 和 JS 为主,CSS 的组件化——less 和 sass * 最早的组件化尝试是把公共的 CSS 样式写成一个个公共 class,但阅读性就变得困难了,也不容易修改。 * less 和 sass 出现之后,使得 CSS 的编程可以定义变量,可以实现继承,CSS 内容的结构也变得更加清晰。
0-3 前端组件化的四原则
* 标准性:任何一个组件都应该遵守一套标准,可以使得不同区域的开发人员据此标准开发出一套标准统一的组件。 * 组合性:组件之间应该是可以组合的。 * 重用性:任何一个组件应该都是一个可以独立的个体,可以使其应用在不同的场景中。 * 可维护性:任何一个组件应该都具有一套自己的完整的稳定的功能,仅包含自身的,与其它组件无关的逻辑。
0-4 传统开发与组件化开发
传统开发与组件化开发: * 对比(标准性、阅读性、复用性、代码冗余、开发效率、维护成本): * 传统前端开发:(难统一、难、难、多、低、高) * 组件化开发:(统一、易、易、基本没冗余、高、低) * 对前端开发者的要求逐步加深: * 传统前端开发:只要求开发者懂 HTML,JS,CSS * 组件化开发:要求开发者掌握 less,sass,或者 ES6 等的语法,以及 Webpack,glup 等的前端打包以及构建工具。 * 前端生态逐渐完善 * jade、less、scss、typeScript 和 webpack 等工具的完善,前端的组件化开发效率已经有了很大的提升。 * 如果你需要 SEO,React 和 Vue 的 SSR 框架 Next.js 和 Nuxt.js 更是提供了开箱即用的集成方案,也使开发“同构页面系统“(Google It)变得更加简单。
0-5 从共识到通用的标准
组件化的开发一直是有共识,但没有一个通用的标准。
Web Components 标准呼之欲出
一、Web Components 标准呼之欲出
Web Component 就是网页组件式开发的技术规范。
* 管理和使用非常容易。加载或卸载组件,只要添加或删除一行代码就可以了。 * 定制非常容易。组件往往留出接口,供使用者设置常见属性,比如上面代码的 heading 属性,就是用来设置对话框的标题。 * 组件是模块化编程思想的体现,非常有利于代码的重用。标准格式的模块,可以跨平台、跨框架使用,构建、部署和与其他UI元素互动都有统一做法。 * 组件提供了 HTML、CSS、JavaScript 封装的方法,实现了与同一页面上其他代码的隔离。
Web Components 不是单一的规范,而是一系列的技术组成,包括 Template Custom Element Shadow DOM HTML Import 四种技术规范。使用时,并不一定这四者都要用到。其中,Custom Element 和 Shadow DOM 最重要,Template 和 HTML Import 只起到辅助作用。
A - Custom Elements
浏览器将自定义元素保留在 DOM 之中,但不会任何语义。除此之外,自定义元素与标准元素都一致。
事实上,浏览器提供了一个HTMLUnknownElement,HTMLElement对象,所有自定义元素都是该对象的实例。
var tabs=document.createElement("tabs");
console.log(tabs instanceof HTMLUnknownElement);//true
console.log(tabs instanceof HTMLElement);//true
Custom Elements 标准:“自定义元素的名字必须包含一个破折号(-)
一旦名字之中使用了破折号,自定义元素就不是HTMLUnknownElement的实例了。
var tabs=document.createElement("my-tabs");
console.log(tabs instanceof HTMLUnknownElement);//false
console.log(tabs instanceof HTMLElement);//true
document.createElement()
Custom Elements 标准规定了,自定义元素的定义可以使用 ES6 的class语法
<my-element content="Custom Element"></my-element>
class MyElement extends HTMLElement {//自定义元素的定义可以使用ES6的class语法
get content() {
return this.getAttribute('content');
}
set content(val) {
this.setAttribute('content', val);
}
}
// 原生的window.customElements对象的define方法用来定义 Custom Element。
// 该方法接受两个参数,第一个参数是自定义元素的名字,第二个参数是一个 ES6 的class。
window.customElements.define('my-element', MyElement);
window.onload=function(){//在页面元素加载完之后,才执行
function customTag(tagName, fn){//Array.from([arguments]);可以将字符串,数组,类数组集合转化为数组
Array
.from(document.getElementsByTagName(tagName))
.forEach(fn);
}
function myElementHandler(element) {
element.textContent = element.content;
}
customTag('my-element', myElementHandler);
};
另一个简单的例子
<my-element content="Custom Element"></my-element>
window.onload = function() {
function customTag(tagName, fn){
console.log(document.getElementsByTagName("div"));
Array .from(document.getElementsByTagName(tagName)).forEach(fn);
}
function greetingHandler(element) {
element.innerHTML = '你好,世界';
}
customTag('greeting', greetingHandler);
}
<greeting>Hello World</greeting>
<greeting>Hello World</greeting>
<greeting>Hello World</greeting>
<style>
greeting{
display:block;
font-size:36px;
color:red;
}
</style>
B - HTML Imports
C - HTML Templates
C-1 概念
<template>元素,基本上可以确定是2013年才出现的,见名知意,模板元素,
C-2 template 标签实战
function supportsTemplate() {
return 'content' in document.createElement('template');
}
if (supportsTemplate()) {
// 支持
} else {
// 不支持
}
检测浏览器是否支持 template
创建一个 template
<template id="profileTemplate">
<div class="profile">
<img src="" class="profile__img">
<div class="profile__name"></div>
<div class="profile__social"></div>
</div>
</template>
var template = document.querySelector('#profileTemplate');
template.content.querySelector('.profile__img').src = 'profile.jpg';
template.content.querySelector('.profile__name').textContent = 'Barack Obama';
template.content.querySelector('.profile__social').textContent = 'Follow me on Twitter';
document.body.appendChild(template.content);
直接修改 template 的模板
创建一个 template
var clone = document.importNode(template.content, true);
document.body.appendChild(clone);
C-2 标签实战
C-3 宿主样式
宿主样式:host:
:host { background: #f8f8f8; } :host(:hover) { background: #ccc; }
::shadow:
/deep/:
::shadow 选择器的一个缺陷是他只能穿透一层影子边界,如果你在一个影子树中嵌套了多个影子树,那么使用 /deep/ 。
::content
通过 标签把来自主文档并添加到 shadow DOM 的内容被称为分布节点。分布节点的样式渲染需要用到 ::content。即使分布节点为em标签,直接写 em {} 不生效,应该写成::content > em {}。
D - Shadow DOM
轻点拍砖。。
By hylerrix