当前位置:3016.com-金沙城中心官网 > 前端 > 致我们终将组件化的Web

致我们终将组件化的Web

文章作者:前端 上传时间:2019-10-11

致大家一定组件化的Web

2015/11/25 · HTML5 · 1 评论 · 组件化

初稿出处: AlloyTeam   

那篇作品将从五年前的一次手艺纠纷起来。争论的聚集便是下图的七个目录分层结构。我说按模块划分好,他说您傻逼啊,当然是按财富划分。

图片 1 《=》图片 2

”按模块划分“目录结构,把如今模块下的具备逻辑和能源都放一块了,那对于多少人独自开辟和维护个人模块不是很好呢?当然了,那争辩的结果是自身婴儿地改回主流的”按财富划分“的目录结构。因为,未有完结JS模块化和能源模块化,仅仅物理地方上的模块划分是尚未意思的,只会追加营造的血本而已。

尽管他说得好有道理笔者哑口无言,不过本人心不甘,等待她近期端组件化成熟了,再来世界首次大战!

最近天就是本身反复正义的小日子!只是那时那些跟你撕逼的人不在。

模块化的阙如

模块平时指能够单独拆分且通用的代码单元。由于JavaScript语言本身并未有放手的模块机制(ES6有了!!),大家平日会使用CMD或ADM创设起模块机制。以往大多数多少大型一点的花色,都会选用requirejs也许seajs来落到实处JS的模块化。多人分工合营开采,其分别定义正视和揭发接口,维护效率模块间独立性,对于项指标支出效能和连串早先时期增加和护卫,都以是有非常的大的援助意义。

但,麻烦大家不怎么略读一下下边的代码

JavaScript

require([ 'Tmpl!../tmpl/list.html','lib/qqapi','module/position','module/refresh','module/page','module/net' ], function(listTmpl, QQapi, Position, Refresh, Page, NET){ var foo = '', bar = []; QQapi.report(); Position.getLocaiton(function(data){ //... }); var init = function(){ bind(); NET.get('/cgi-bin/xxx/xxx',function(data){ renderA(data.banner); renderB(data.list); }); }; var processData = function(){ }; var bind = function(){ }; var renderA = function(){ }; var renderB = function(data){ listTmpl.render('#listContent',processData(data)); }; var refresh = function(){ Page.refresh(); }; // app start init(); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
require([
    'Tmpl!../tmpl/list.html','lib/qqapi','module/position','module/refresh','module/page','module/net'
], function(listTmpl, QQapi, Position, Refresh, Page, NET){
    var foo = '',
        bar = [];
    QQapi.report();
    Position.getLocaiton(function(data){
        //...
    });
    var init = function(){
        bind();
        NET.get('/cgi-bin/xxx/xxx',function(data){
            renderA(data.banner);
            renderB(data.list);
        });
    };
    var processData = function(){
    };
    var bind = function(){
    };
    var renderA = function(){
    };
    var renderB = function(data){
        listTmpl.render('#listContent',processData(data));
    };
    var refresh = function(){
        Page.refresh();
    };
    // app start
    init();
});

地点是现实某些页面包车型地铁主js,已经封装了像Position,NET,Refresh等功用模块,但页面包车型大巴主逻辑依旧是”面向进度“的代码结构。所谓面向进程,是指依据页面包车型地铁渲染进度来编排代码结构。像:init -> getData -> processData -> bindevent -> report -> xxx 。 方法之间线性跳转,你大致也能感受那样代码缺欠。随着页面逻辑更是复杂,那条”进程线“也会越来越长,况且更为绕。加之贫乏专门的职业约束,别的类型成员依据各自必要,在”进程线“加插各自逻辑,最后那么些页面包车型客车逻辑变得难以维护。

图片 3

支付须要留意,生怕影响“进程线”后边正常逻辑。并且每便加插或改造都是bug泛滥,无不令产品有关人口无不诚惶诚惧。

 页面结构模块化

依照下边包车型客车面向进程的难点,行当内也会有成百上千施工方案,而大家协会也计算出一套成熟的消除方案:Abstractjs,页面结构模块化。大家得以把大家的页面想象为三个乐高机器人,要求分歧零件组装,如下图,即使页面划分为tabContainer,listContainer和imgsContainer七个模块。最后把这个模块add到结尾的pageModel里面,最终利用rock方法让页面运转起来。

图片 4
(原经过线示例图)

图片 5
(页面结构化示例图)

上边是伪代码的完结

JavaScript

require([ 'Tmpl!../tmpl/list.html','Tmpl!../tmpl/imgs.html','lib/qqapi','module/refresh','module/page' ], function(listTmpl, imgsTmpl, QQapi, Refresh, Page ){ var tabContainer = new RenderModel({ renderContainer: '#tabWrap', data: {}, renderTmpl: "<li soda-repeat='item in data.tabs'>{{item}}</li>", event: function(){ // tab's event } }); var listContainer = new ScrollModel({ scrollEl: $.os.ios ? $('#Page') : window, renderContainer: '#listWrap', renderTmpl: listTmpl, cgiName: '/cgi-bin/index-list?num=1', processData: function(data) { //... }, event: function(){ // listElement's event }, error: function(data) { Page.show('数据再次来到十分[' + data.retcode + ']'); } }); var imgsContainer = new renderModel({ renderContainer: '#imgsWrap', renderTmpl: listTmpl, cgiName: '/cgi-bin/getPics', processData: function(data) { //... }, event: function(){ // imgsElement's event }, complete: function(data) { QQapi.report(); } }); var page = new PageModel(); page.add([tabContainer,listContainer,imgsContainer]); page.rock(); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
require([
    'Tmpl!../tmpl/list.html','Tmpl!../tmpl/imgs.html','lib/qqapi','module/refresh','module/page'
], function(listTmpl, imgsTmpl, QQapi, Refresh, Page ){
 
    var tabContainer = new RenderModel({
        renderContainer: '#tabWrap',
        data: {},
        renderTmpl: "<li soda-repeat='item in data.tabs'>{{item}}</li>",
        event: function(){
            // tab's event
        }
    });
 
    var listContainer = new ScrollModel({
        scrollEl: $.os.ios ? $('#Page') : window,
        renderContainer: '#listWrap',
        renderTmpl: listTmpl,
        cgiName: '/cgi-bin/index-list?num=1',
        processData: function(data) {
            //...
        },
        event: function(){
            // listElement's event
        },
        error: function(data) {
            Page.show('数据返回异常[' + data.retcode + ']');
        }
    });
 
    var imgsContainer = new renderModel({
        renderContainer: '#imgsWrap',
        renderTmpl: listTmpl,
        cgiName: '/cgi-bin/getPics',
        processData: function(data) {
            //...
        },
        event: function(){
            // imgsElement's event
        },
        complete: function(data) {
           QQapi.report();
        }
    });
 
    var page = new PageModel();
    page.add([tabContainer,listContainer,imgsContainer]);
    page.rock();
 
});

笔者们把那几个常用的伸手CGI,管理数据,事件绑定,上报,容错管理等一多级逻辑格局,以页面块为单位封装成一个Model模块。

如此的一个浮泛层Model,大家得以清楚地来看该页面块,伏乞的CGI是怎么,绑定了哪些风云,做了哪些上报,出错怎么管理。新扩大的代码就应有放置在相应的模块上相应的景况方法(preload,process,event,complete…),杜绝了过去的不可能规乱增代码的编著。而且,依照差别专门的学问逻辑封装分裂门类的Model,如列表滚动的ScrollModel,滑块功效的SliderModel等等,可以开展高度封装,聚集优化。

现行反革命依据Model的页面结构开采,已经包蕴一点”组件化“的味道。各个Model都满含各自的数目,模板,逻辑。已经算是二个完好无缺的效果与利益单元。但相距真正的WebComponent照旧有一段间隔,最少满意不断作者的”理想目录结构“。

 WebComponents 标准

小编们回顾一下用到二个datapicker的jquery的插件,所急需的步奏:

  1. 引进插件js

  2. 引进插件所需的css(若是有)

  3. copy 组件的所需的html片段

  4. 拉长代码触发组件运行

当下的“组件”基本上只好到达是某些成效单元上的汇合。他的能源都以松散地分散在三种能源文件中,何况组件功能域揭发在大局意义域下,缺乏内聚性很轻松就能跟别的零件产生冲突,如最简便易行的css命名矛盾。对于这种“组件”,还不比上边的页面结构模块化。

于是乎W3C按耐不住了,制订贰个WebComponents标准,为组件化的前程引导了明路。

上边以较为轻巧的章程介绍那份正经,力求我们可以高效掌握完成组件化的原委。(对那部分叩问的同窗,能够跳过这一小节)

1. <template>模板技艺

模板这东西大家最熟识可是了,前一年见的相当多的模版质量战争artTemplate,juicer,tmpl,underscoretemplate等等。而现行反革命又有mustachejs无逻辑模板引擎等新入选手。但是大家有未有想过,这么基础的力量,原生HTML5是不支持的(T_T)。

近些日子天WebComponent将在提供原生的模板本领

XHTML

<template id="datapcikerTmpl"> <div>笔者是原生的沙盘</div> </template>

1
2
3
<template id="datapcikerTmpl">
<div>我是原生的模板</div>
</template>

template标签钦赐义了myTmpl的沙盘,供给采用的时候就要innerHTML= document.querySelector('#myTmpl').content;能够看出这几个原生的模版够原始,模板占位符等职能都未有,对于动态数据渲染模板手艺只好自力更新。

2. ShadowDom 封装组件独立的内部结构

ShadowDom能够领略为一份有独立功效域的html片段。这个html片段的CSS境遇和主文书档案隔绝的,各自笔者保护持内部的独立性。也正是ShadowDom的独自本性,使得组件化成为了恐怕。

JavaScript

var wrap = document.querySelector('#wrap'); var shadow = wrap.createShadowRoot(); shadow.innerHTML = '<p>you can not see me </p>'

1
2
3
var wrap = document.querySelector('#wrap');
var shadow = wrap.createShadowRoot();
shadow.innerHTML = '<p>you can not see me </p>'

在实际dom节点上运用createShadowRoot方法就能够生成其ShadowDom。就好像在整份Html的房子里面,新建了多少个shadow的房间。房间外的人都不知道房间内有哪些,保持shadowDom的独立性。

3. 自定义原生标签

最初接触Angularjs的directive指令功用,设定好组件的逻辑后,贰个<Datepicker />就能够引进整个组件。如此狂炫目炸碉堡天的功用,实在令人拍手称快,跃地三尺。

JavaScript

var tmpl = document.querySelector('#datapickerTmpl'); var datapickerProto = Object.create(HTMLElement.prototype); // 设置把我们模板内容咱们的shadowDom datapickerProto.createdCallback = function() { var root = this.createShadowRoot(); root.appendChild(document.importNode(tmpl.content, true)); }; var datapicker = docuemnt.registerElement('datapicker',{ prototype: datapickerProto });

1
2
3
4
5
6
7
8
9
10
11
12
var tmpl = document.querySelector('#datapickerTmpl');
var datapickerProto = Object.create(HTMLElement.prototype);
 
// 设置把我们模板内容我们的shadowDom
datapickerProto.createdCallback = function() {
    var root = this.createShadowRoot();
    root.appendChild(document.importNode(tmpl.content, true));
};
 
var datapicker = docuemnt.registerElement('datapicker',{
    prototype: datapickerProto
});

Object.create情势接二连三HTMLElement.prototype,得到一个新的prototype。当深入分析器开掘我们在文书档案中标识它将检查是或不是一个名称为createdCallback的措施。倘使找到这些法子它将马上运营它,所以大家把克隆模板的开始和结果来创建的ShadowDom。

聊到底,registerElement的办法传递大家的prototype来注册自定义标签。

地方的代码初始略显复杂了,把后边多个力量“模板”“shadowDom”结合,产生组件的里边逻辑。最后通过registerElement的格局注册组件。之后方可欢跃地<datapicker></datapicker>的使用。

4. imports消除组件间的正视性

XHTML

<link rel="import" href="datapciker.html">

1
<link rel="import" href="datapciker.html">

其一类php最常用的html导入功效,HTML原生也能支撑了。

WebComponents标准内容差不多到这里,是的,笔者这边未有啥样Demo,也尚无实施经验分享。由于webComponents新个性,基本上巳了高版本的Chrome扶助外,别的浏览器的支撑度甚少。即便有polymer扶助拉动webcompoents的仓库储存在,不过polymer自个儿的渴求版本也是至非常高(IE10+)。所从前些天的台柱并不是她。

咱俩大致来回想一下WebCompoents的四部分功效:

1 .<template>定义组件的HTML模板技能

  1. Shadow Dom封装组件的内部结构,而且维持其独立性

  2. Custom Element 对外提供组件的标签,实现自定义标签

  3. import化解组件结合和信任加载

 组件化推行方案

法定的正儿八经看完了,我们观念一下。一份真正成熟笃定的组件化方案,供给持有的工夫。

“能源高内聚”—— 组件财富内部高内聚,组件财富由自个儿加载调整

“功效域独立”—— 内部结构密闭,不与大局或任何零件产生影响

“自定义标签”—— 定义组件的运用方法

“可互相结合”—— 组件正在有力的地方,组件间组装整合

“接口规范化”—— 组件接口有统一标准,或然是生命周期的治本

私家感到,模板技能是基础技能,跟是还是不是组件化未有强联系,所以并未提议多个大点。

既然如此是实行,现阶段WebComponent的支撑度还不成熟,不可能同日而语方案的一手。而别的一套以高质量设想Dom为切入点的零件框架React,在facebook的造势下,社区收获了大力发展。别的一名骨干Webpack,肩负化解组件财富内聚,同期跟React极度适合形成补充。

所以【Webpack】+【React】将会是那套方案的大旨本事。

不领悟你现在是“又是react+webpack”认为失望图片 6,仍然“太好了是react+webpack”不用再学贰遍新框架的喜出望外图片 7。无论如何上边包车型地铁内容不会令你失望的。

一,组件生命周期

图片 8

React天生正是强制性组件化的,所以可以从根脾性上消除面向进程代码所带动的劳动。React组件本人有生命周期方法,可以满意“接口标准化”技巧点。而且跟“页面结构模块化”的所封装抽离的多少个方法能挨个对应。别的react的jsx自带模板成效,把html页面片直接写在render方法内,组件内聚性越发紧凑。

由于React编写的JSX是会先生成设想Dom的,须求机会才真正插入到Dom树。使用React必供给明了组件的生命周期,其生命周期多个状态:

Mount: 插入Dom

Update: 更新Dom

Unmount: 拔出Dom

mount那单词翻译扩大,嵌入等。笔者倒是提议“插入”越来越好精通。插入!拔出!插入!拔出!默念一遍,懂了没?别少看黄段子的力量,

图片 9

零件状态正是: 插入-> 更新 ->拔出。

下一场每一个组件状态会有二种管理函数,一前一后,will函数和did函数。

componentWillMount()  企图插入前

componentDidlMount()  插入后

componentWillUpdate() 希图更新前

componentDidUpdate()  更新后

componentWillUnmount() 策画拔出前

因为拔出后为主都以贤者形态(作者说的是组件),所以未有DidUnmount那么些方法。

除此以外React别的三个主干:数据模型props和state,对应着也许有自个状态方法

getInitialState()     获取早先化state。

getDefaultProps() 获取暗中认可props。对于那贰个尚未父组件传递的props,通过该措施设置暗中认可的props

componentWillReceiveProps()  已插入的零件收到新的props时调用

再有三个不相同日常景况的管理函数,用于优化管理

shouldComponentUpdate():决断组件是或不是必要update调用

增添最关键的render方法,React本人带的章程刚刚好十个。对于初读书人的话是相比较难以消化吸取。但其实getInitialStatecomponentDidMountrender四个情景方法都能幸不辱命抢先48%零件,不必惧怕。

回来组件化的核心。

八个页面结构模块化的零件,能独立包装整个组件的进程线

图片 10

我们换算成React生命周期方法:

图片 11

 

零件的情状方法流中,有两点需求极其表明:

1,三次渲染:

鉴于React的杜撰Dom个性,组件的render函数不需协和触发,依据props和state的改观自个通过差别算法,得出最优的渲染。

伸手CGI一般都以异步,所以无可置疑带来一次渲染。只是空数据渲染的时候,有望会被React优化掉。当数码回来,通过setState,触发贰回render

 

2,componentWiillMount与componentDidMount的差别

和大好些个React的教程小说不相同,ajax诉求笔者建议在威尔Mount的情势内实施,并非组件起始化成功之后的DidMount。那样能在“空数据渲染”阶段以前须求数据,尽早地降低一回渲染的时日。

willMount只会施行一回,极其相符做init的业务。

didMount也只会施行贰回,并且那时候真实的Dom已经酿成,非常切合事件绑定和complete类的逻辑。

 

 二,JSX极难看,不过组件内聚的重要!

WebComponents的行业内部之一,需求模板技艺。本是以为是大家耳熟能详的沙盘技能,但React中的JSX那样的奇人依旧令人争辩纷纭。React还并未有火起来的时候,大家就曾在和讯上尖锐地戏弄了“JSX写的代码那TM的丑”。那其实只是Demo阶段JSX,等到实战的大型项目中的JSX,满含多情形比很多据多事件的时候,你会发现………….JSX写的代码依然非常难看。

图片 12
(即便用sublime-babel等插件高亮,逻辑和渲染耦合一同,阅读性依旧略差)

缘何我们会感到丑?因为大家已经经对“视图-样式-逻辑”分离的做法潜濡默化。

基于维护性和可读性,乃至质量,大家都不提议直接在Dom下边绑定事件或许直接写style属性。大家会在JS写事件代理,在CSS上写上classname,html上的正是清楚的Dom结构。大家很好地维护着MVC的设计格局,一切有惊无险。直到JSX把他们都夹杂在一同,所守护的本领栈受到侵袭,难免存有抗拒。

 

不过从组件化的指标来看,这种高内聚的做法未尝不可。

下边包车型地铁代码,从前的“逻辑视图分离”方式,大家必要去找相应的js文件,相应的event函数体内,找到td-info的class所绑定的风云。

比较之下起JSX的万丈内聚,所有的事件逻辑正是在自个儿jsx文件内,绑定的正是本人的showInfo方法。组件化的性情能立刻显示出来。

(注意:尽管写法上大家好疑似HTML的内联事件管理器,不过在React底层并不曾实际赋值类似onClick属性,内层照旧选择类似事件代理的法子,高效地维护着事件管理器)

再来看一段style的jsx。其实jsx未有对体制有硬性规定,大家全然可遵从从前的定义class的逻辑。任何一段样式都应该用class来定义。在jsx你也全然能够这么做。不过出于组件的独立性,小编提出部分只有“叁次性”的体裁直接运用style赋值越来越好。减少冗余的class。

XHTML

<div className="list" style={{background: "#ddd"}}> {list_html} </div>

1
2
3
<div className="list" style={{background: "#ddd"}}>
   {list_html}
</div>

莫不JSX内部有肩负繁琐的逻辑样式,可JSX的自定义标签能力,组件的黑盒性立马能体会出来,是否瞬间美好了无数。

JavaScript

render: function(){ return ( <div> <Menus bannerNums={this.state.list.length}></Menus> <TableList data={this.state.list}></TableList> </div> ); }

1
2
3
4
5
6
7
8
render: function(){
    return (
      <div>
         <Menus bannerNums={this.state.list.length}></Menus>
         <TableList data={this.state.list}></TableList>
      </div>
   );
}

就算JSX本质上是为着虚构Dom而打算的,但这种逻辑和视图中度合一对于组件化未尝不是一件善事。

 

学学完React这几个组件化框架后,看看组件化本领点的到位意况

“能源高内聚”—— (33%)  html与js内聚

“作用域独立”—— (四分之二)  js的成效域独立

“自定义标签”—— (百分百)jsx

“可互相结合”—— (二分一)  可构成,但贫乏可行的加载格局

“接口标准化”—— (百分之百)组件生命周期方法

 

Webpack 能源组件化

对此组件化的财富独立性,常常的模块加载工具和创设流程视乎变得吃力。组件化的构建筑工程程化,不再是事先大家常见的,css合二,js合三,而是体验在组件间的依赖于加载关系。webpack正好符合要求点,一方面填补组件化工夫点,另一方援救大家完善组件化的全部塑造情形。

首先要说澳优(Ausnutria Hyproca)点是,webpack是一个模块加载打包工具,用于处理你的模块能源注重打包难题。那跟大家耳闻则诵的requirejs模块加载工具,和grunt/gulp构建筑工程具的定义,多多少少有个别出入又有个别雷同。

图片 13

首先webpak对于CommonJS与英特尔同一时间援助,满足大家模块/组件的加载格局。

JavaScript

require("module"); require("../file.js"); exports.doStuff = function() {}; module.exports = someValue;

1
2
3
4
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;

JavaScript

define("mymodule", ["dep1", "dep2"], function(d1, d2) { return someExportedValue; });

1
2
3
define("mymodule", ["dep1", "dep2"], function(d1, d2) {
    return someExportedValue;
});

自然最强劲的,最卓绝的,当然是模块打包功用。这多亏这一成效,补充了组件化财富注重,乃至完整工程化的本事

依赖webpack的计划观念,全体财富都以“模块”,webpack内部贯彻了一套财富加运载飞机制,能够把想css,图片等能源等有依据关系的“模块”加载。那跟我们运用requirejs这种单纯管理js大大不一样。而那套加运载飞机制,通过一个个loader来达成。

 

JavaScript

// webpack.config.js module.exports = { entry: { entry: './index.jsx', }, output: { path: __dirname, filename: '[name].min.js' }, module: { loaders: [ {test: /.css$/, loader: 'style!css' }, {test: /.(jsx|js)?$/, loader: 'jsx?harmony', exclude: /node_modules/}, {test: /.(png|jpg|jpeg)$/, loader: 'url-loader?limit=10240'} ] } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// webpack.config.js
module.exports = {
    entry: {
     entry: './index.jsx',
    },
    output: {
        path: __dirname,
        filename: '[name].min.js'
    },
    module: {
        loaders: [
            {test: /.css$/, loader: 'style!css' },
            {test: /.(jsx|js)?$/, loader: 'jsx?harmony', exclude: /node_modules/},
            {test: /.(png|jpg|jpeg)$/, loader: 'url-loader?limit=10240'}
        ]
    }
};

地点一份轻巧的webpack配置文件,在乎loaders的布置,数组内二个object配置为一种模块能源的加运载飞机制。test的正则为同盟文件法则,loader的为相称到文件将由什么加载器管理,三个计算机之间用相隔,管理顺序从右到左。

 

style!css,css文件通过css-loader(管理css),再到style-loader(inline到html)的加工管理流。

jsx文件通过jsx-loader编写翻译,‘?’开启加载参数,harmony帮助ES6的语法。

图片能源通过url-loader加载器,配置参数limit,调控少于10KB的图样将会base64化。

 财富文件怎样被require?

JavaScript

// 加载组件本人css require('./slider.css'); // 加载组件正视的模块 var Clip = require('./clipitem.js'); // 加载图片财富 var spinnerImg = require('./loading.png');

1
2
3
4
5
6
// 加载组件自身css
require('./slider.css');
// 加载组件依赖的模块
var Clip = require('./clipitem.js');
// 加载图片资源
var spinnerImg = require('./loading.png');

在webpack的js文件中大家除了require大家如常的js文件,css和png等静态文件也能够被require进来。大家由此webpack命令,编译之后,看看输出结果什么:

JavaScript

webpackJsonp([0], { /* 0 */ /***/ function(module, exports, __webpack_require__) { // 加载组件自个儿css __webpack_require__(1); // 加载组件依赖的模块 var Clip = __webpack_require__(5); // 加载图片财富 var spinnerImg = __webpack_require__(6); /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { exports = module.exports = __webpack_require__(3)(); exports.push([module.id, ".slider-wrap{rn position: relative;rn width: 100%;rn margin: 50px;rn background: #fff;rn}rnrn.slider-wrap li{rn text-align: center;rn line-height: 20px;rn}", ""]); /***/ }, /* 3 */ /***/ function(module, exports) { /***/ }, /* 4 */ /***/ function(module, exports, __webpack_require__) { /***/ }, /* 5 */ /***/ function(module, exports) { console.log('hello, here is clipitem.js') ; /***/ }, /* 6 */ /***/ function(module, exports) { module.exports = "data:image/png;base64,iVBORw0KGg......" /***/ } ]);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
webpackJsonp([0], {
/* 0 */
/***/ function(module, exports, __webpack_require__) {
          // 加载组件自身css
          __webpack_require__(1);
          // 加载组件依赖的模块
          var Clip = __webpack_require__(5);
          // 加载图片资源
          var spinnerImg = __webpack_require__(6);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
 
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
          exports = module.exports = __webpack_require__(3)();
          exports.push([module.id, ".slider-wrap{rn position: relative;rn width: 100%;rn margin: 50px;rn background: #fff;rn}rnrn.slider-wrap li{rn text-align: center;rn line-height: 20px;rn}", ""]);
 
/***/ },
/* 3 */
/***/ function(module, exports) {
 
/***/ },
 
/* 4 */
/***/ function(module, exports, __webpack_require__) {
/***/ },
 
/* 5 */
/***/ function(module, exports) {
          console.log('hello, here is clipitem.js') ;
/***/ },
/* 6 */
/***/ function(module, exports) {
          module.exports = "data:image/png;base64,iVBORw0KGg......"
/***/ }
]);

webpack编写翻译之后,输出文件视乎乱糟糟的,但实际上每二个财富都被封装在多少个函数体内,並且以编号的款型标识(注释)。这几个模块,由webpack的__webpack_require__内部方法加载。入口文件为编号0的函数index.js,能够见见__webpack_require__加载别的编号的模块。

css文件在数码1,由于使用css-loader和style-loader,编号1-4都以管理css。在那之中编号2大家得以看大家的css的string体。最后会以内联的不二法门插入到html中。

图表文件在编号6,能够看出exports出base64化的图纸。

 组件一体输出

JavaScript

// 加载组件自个儿css require('./slider.css'); // 加载组件注重的模块 var React = require('react'); var Clip = require('../ui/clipitem.jsx'); // 加载图片能源 var spinnerImg = require('./loading.png'); var Slider = React.createClass({ getInitialState: function() { // ... }, componentDidMount: function(){ // ... }, render: function() { return ( <div> <Clip data={this.props.imgs} /> <img className="loading" src={spinnerImg} /> </div> ); } }); module.exports = Slider;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 加载组件自身css
require('./slider.css');
// 加载组件依赖的模块
var React = require('react');
var Clip = require('../ui/clipitem.jsx');
// 加载图片资源
var spinnerImg = require('./loading.png');
var Slider = React.createClass({
    getInitialState: function() {
        // ...
    },
    componentDidMount: function(){
        // ...
    },
    render: function() {
        return (
            <div>
               <Clip data={this.props.imgs} />
               <img className="loading" src={spinnerImg} />
            </div>
        );
    }
});
module.exports = Slider;

假设说,react使到html和js合为紧密。

那么丰盛webpack,两个结合一同的话。js,css,png(base64),html 全体web财富都能合成二个JS文件。那多亏这套方案的着力所在:组件独立一体化。如若要引用一个组件,仅仅require('./slider.js') 就可以实现。

 

加入webpack的模块加载器之后,大家组件的加载难点,内聚难点也都职业有成地消除掉

“能源高内聚”—— (百分百) 全数能源能够一js出口

“可互相结合”—— (百分百)  可整合可依据加载

 

 CSS模块化实行

很高兴,你能阅读到那边。近日大家的组件完结度极度的高,能源内聚,易于组合,成效域独立互不污染。。。。等等图片 14,视乎CSS模块的完毕度有不足。

那么如今组件完成度来看,CSS效率域其实是全局性的,并不是组件内部独立。下一步,大家要做得正是哪些让大家组件内部的CSS效能域独立。

此时大概有人马上跳出,大喊一句“德玛西亚!”,哦不,应该是“用sass啊傻逼!”。但是品种组件化之后,组件的中间封装已经很好了,个中间dom结商谈css趋向轻松,独立,以致是破破烂烂的。LESS和SASS的一体式样式框架的设计,他的嵌套,变量,include,函数等丰盛的作用对于全部大型项目标体制管理特别实用。但对此三个效应单一组件内部样式,视乎就变的多少水火不容。“不可能为了框架而框架,合适才是最佳的”。视乎原生的css本事已经满意组件的体裁须求,唯独便是上边的css成效域难点。

 

此间自个儿付诸思虑的方案: classname随意写,保持原生的主意。编译阶段,依照组件在项目路径的独一性,由【组件classname+组件独一路线】打成md5,生成全局独一性classname。正当自身要写四个loader实现本人的主见的时候,开采歪果仁已经早在先走一步了。。。。

此间具体方案参谋小编事先博客的译文:

事先大家探讨过JS的模块。未来经过Webpack被加载的CSS财富叫做“CSS模块”?作者觉着照旧有标题标。未来style-loader插件的落成精神上只是创设link[rel=stylesheet]要素插入到document中。这种行为和普通引进JS模块特别分化。引进另二个JS模块是调用它所提供的接口,但引进一个CSS却并不“调用”CSS。所以引进CSS本人对于JS程序来讲并不设有“模块化”意义,纯粹只是表达了一种能源正视——即该器件所要完毕的功效还索要或多或少asset。

因而,那位歪果仁还扩张了“CSS模块化”的概念,除了上边的大家须要部分作用域外,还会有许多效果,这里不详述。具体参照他事他说加以考察原作 

丰富赞的一点,正是cssmodules已经被css-loader收纳。所以我们没有需求依据额外的loader,基本的css-loader开启参数modules就可以

JavaScript

//webpack.config.js ... module: { loaders: [ {test: /.css$/, loader: 'style!css?modules&localIdentName=[local]__[name]_[hash:base64:5]' }, ] } ....

1
2
3
4
5
6
7
8
//webpack.config.js
...  
    module: {
        loaders: [
            {test: /.css$/, loader: 'style!css?modules&localIdentName=[local]__[name]_[hash:base64:5]' },
        ]  
    }
....

modules参数代表开启css-modules作用,loaclIdentName为设置大家编写翻译后的css名字,为了有助于debug,大家把classname(local)和组件名字(name)输出。当然能够在最后输出的版本为了省去提交,仅仅使用hash值即可。别的在react中的用法大约如下。

JavaScript

var styles = require('./banner.css'); var Banner = new React.createClass({ ... render: function(){ return ( <div> <div className={styles.classA}></div> </div> ) } });

1
2
3
4
5
6
7
8
9
10
11
var styles = require('./banner.css');
var Banner = new React.createClass({
    ...
    render: function(){
        return (
            <div>
                <div className={styles.classA}></div>
            </div>
        )
    }
});

终极这里关于出于对CSS一些斟酌,

至于css-modules的任何效用,小编并不图谋动用。在内部分享【咱们竭尽所能地让CSS变得复杂】中谈起:

大家项目中大部的CSS都不会像boostrap这样供给变量来安装,身为一线开荒者的大家大要能够感受到:设计员们改版UI,相对不是回顾的换个色或改个间隔,而是气象一新的全新UI,那纯属不是叁个变量所能消除的”维护性“。

反而项目实战进程中,真正要化解的是:在本子迭代进度中那么些淘汰掉的过期CSS,大批量地堆集在项目个中。大家像极了家中的欧巴酱不舍得吐弃没用的东西,因为那只是我们运用sass或less编写出具备惊人的可维护性的,肯定有复用的一天。

那些积聚的过期CSS(or sass)之间又有部分信任,一部分超时失效了,一部分又被新的体裁复用了,导致没人敢动那几个历史样式。结果现网项目迭代还带着多量七年前没用的样式文件。

组件化之后,css的格局同样被改造了。只怕postcss才是您未来手上最切合的工具,而不在是sass。

 

到此处,大家总算把组件化最后四个标题也解决了。

“成效域独立”—— (100%) 就如shadowDom功能域独立

 

到此地,大家可以开一瓶82年的Coca Cola,好好庆祝一下。不是吧?

图片 15

 

 组件化之路还在继续

webpack和react还也是有数不清新比较重大的性状和功力,介于本文仅仅围绕着组件化的为主导,未有各类演讲。别的,配搭gulp/grunt补充webpack营造技艺,webpack的codeSplitting,react的零件通讯难题,开采与生育情况安排等等,都以整整大型项目方案的所必得的,限于篇幅难题。能够等等我更新下篇,或大家能够自行查阅。

然则,不得不再安利一下react-hotloader神器。热加载的费用情势相对是下一代前端开拓必备。严俊说,若是没有了热加载,笔者会很坚决地遗弃那套方案,就算那套方案再怎么完美,小编都讨厌react需求5~6s的编写翻译时间。不过hotloader可以在自家不刷新页面包车型大巴景观下,动态修改代码,何况不单单是样式,连逻辑也是即时生效。

图片 16

如上在form表单内。使用热加载,表单无需再行填写,修改submit的逻辑立刻见效。那样的支出效能真不是进步仅仅三个水平。必需安利一下。

 

可能你发掘,使用组件化方案现在,整个工夫栈都被更新了一番。学习成本也不少,並且能够预看见,基于组件化的前端还有大概会过多供应不能够满足要求的主题材料,举例品质优化方案须求重新考虑,以致最基本的机件可复用性不必然高。前面相当短一段时间,需求大家不停锻练与优化,查究最优的前端组件化之道。

足足大家能够想象,不再忧虑本人写的代码跟有些何人哪个人矛盾,不再为找某段逻辑在多少个文件和措施间穿梭,不再copy一片片逻辑然后改改。大家每一回编写都以可选择,可结合,独立且内聚的零部件。而各种页面将会由叁个个嵌套组合的机件,相互独立却相互成效。

 

对此那样的前端以后,有所指望,不是很好呢

迄今,谢谢您的读书。

1 赞 6 收藏 1 评论

图片 17

本文由3016.com-金沙城中心官网发布于前端,转载请注明出处:致我们终将组件化的Web

关键词: