前端开荒框架,前端组件化开采施行
分类:前端技术

前面一个组件化开采推行

2015/07/12 · CSS, HTML5, JavaScript · 组件化

原稿出处: 美团手艺博客 - spring   

致大家必然组件化的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标准内容大约到此处,是的,笔者这里没有何样德姆o,也一贯不施行经验分享。由于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本人带的不二等秘书技刚刚好12个。对于初读书人的话是相比较为难消食。但实际getInitialStatecomponentDidMountrender多个状态方法都能不负众望超越八分之四组件,不必惧怕。

归来组件化的主题。

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

图片 10

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

图片 11

 

零件的气象方法流中,有两点必要新鲜表明:

1,一回渲染:

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

需要CGI日常都以异步,所以自然带来三回渲染。只是空数据渲染的时候,有十分大希望会被React优化掉。当数码回来,通过setState,触发三遍render

 

2,componentWiillMount与componentDidMount的差别

和大好些个React的学科小说不等同,ajax须要笔者建议在WillMount的法子内施行,而不是组件最初化成功以往的DidMount。那样能在“空数据渲染”阶段早先诉求数据,尽早地缩减一回渲染的光阴。

willMount只会执行二次,特别相符做init的事务。

didMount也只会实行三次,并且那时候真实的Dom已经变成,特别切合事件绑定和complete类的逻辑。

 

 二,JSX好丑,可是组件内聚的重视!

WebComponents的行业内部之一,要求模板工夫。本是感到是大家耳濡目染的模板技艺,但React中的JSX那样的怪物依旧让人研究纷繁。React还尚未火起来的时候,大家就早就在网易上狠狠地作弄了“JSX写的代码那TM的丑”。那实则只是德姆o阶段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正好符合须要点,一方面填补组件化手艺点,另一方扶持大家周详组件化的完好创设境况。

率先要表达一(Wissu)点是,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。

 

到这里,我们究竟把组件化最后五个主题材料也解决了。

“效能域独立”—— (百分之百) 就好像shadowDom功能域独立

 

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

图片 15

 

 组件化之路还在继续

webpack和react还应该有过多新相当的重大的风味和法力,介于本文仅仅围绕着组件化的为基本,未有各样演说。其他,配搭gulp/grunt补充webpack构建本领,webpack的codeSplitting,react的零件通讯难题,开垦与生产条件布置等等,都以漫天天津大学学型项目方案的所不可不的,限于篇幅难点。能够等等我更新下篇,或大家能够自行查阅。

而是,不得不再安利一下react-hotloader神器。热加载的开辟方式相对是下一代前端开拓必备。严厉说,假若未有了热加载,我会很泼辣地放任那套方案,纵然那套方案再怎么可以,我都讨厌react需求5~6s的编写翻译时间。然则hotloader可以在本人不刷新页面包车型客车景况下,动态修改代码,并且不单单是样式,连逻辑也是即时生效。

图片 16

如上在form表单内。使用热加载,表单无需再一次填写,修改submit的逻辑登时见效。那样的费用功用真不是增加仅仅三个水平。必须安利一下。

 

或者你意识,使用组件化方案现在,整个技巧栈都被更新了一番。学习成本也不菲,况兼能够预认为,基于组件化的前端还大概会过多不足的主题素材,比如品质优化方案需求再度考虑,以至最大旨的组件可复用性不自然高。前面不长一段时间,需求大家不住磨砺与优化,查究最优的前端组件化之道。

足足大家得以设想,不再思量本身写的代码跟某些什么人哪个人冲突,不再为找某段逻辑在五个文件和艺术间穿梭,不再copy一片片逻辑然后改改。大家每一遍编写都以可采纳,可整合,独立且内聚的机件。而种种页面将会由二个个嵌套组合的零件,互相独立却互相作用。

 

对此如此的前端现在,有所指望,不是很好吧

迄今结束,谢谢您的读书。

1 赞 6 收藏 1 评论

图片 17

摘要


  • 后端懒人一枚,不常须求搞个管理端,以往在全校有用jquery bootstrap做过类似的前端项目,但是现在回顾,旧代码如屎一坨,更别提维护了。有了事先的训诲,境遇这一个供给就调节认真做做。
  • 对前面三个照旧略小白,写得不得了,还望多都赐教。
  • 已成功的品种利用的重组是react webpack redux-form(扶植ie8)

正文介绍seajs和hanlebars,并完毕前端控件组件化.

前言

一人计算机前辈曾说过:

Controlling complexity is the essence of computer programming

1
Controlling complexity is the essence of computer programming

乘机前端开垦复杂度的逐年晋级,组件化开辟应时而生,并乘机 FIS、React 等奇妙框架的面世随处开花。这一历程一样发生在美团,面对职业规模的高速提升和技术员团队的不断扩张,大家历经引进组件消除决能源整合难点、稳步坚实组件功效推动开辟成效、重新创设新一代组件化方案适应全栈开垦和分享一起创建等阶段,努力“controlling complexity”。本文将介绍大家组件化开荒的施行进度。

背景与主题材料


  • Header,Banner,Footer等前端布局的集体部分,重复编写代码或倚靠php等后端语言举办渲染,会招致前后端代码高耦合。
  • 屏弃全局变量的留存,给品种增添带来未知难题。
  • 趁着项目支出持续举办,项目也会变得臃肿,不佳的门类组织会使有限扶助专门的学问越是困难。复杂的页面需求调控越来越多景况,并根据情状的变型,施行越多相应的逻辑。
  • 本着管理端,进行ie8 的优秀。
  • 应用的第三方库很多,前端发送的静态文件(js,css)伏乞很多,导致网页加载速度异常的慢。
  • 管住平台的样式多有同等,若样式定制开荒,会生出不须要的专门的学问量。

小编想实现的是把组件单独三个文书夹,js和css,html都位居文件夹中,要接纳组件的页面使用seajs引进组件,并直接调用组件的不二等秘书诀照旧事件。这些方案是和谐的切磋,应接大家拍砖。

组件化 1.0:财富整合

在美团开始的一段时期,前端能源是遵从页面可能类似事情页面集结的情势张开集体的。举例order.js 对应订单相关页面的相互,account.css 对应账户相关页面包车型大巴样式。这种艺术在过去的较长一段时间内,持续帮助了方方面面项目标正规推动,居功至伟。

图片 18

随着业务规模的扩张和支付公司的强大,那套机制稳步呈现出它的局地相差:

  • 财富冗余页面包车型地铁逐月增加,交互的逐月复杂化,导致对应的 css 和 js 都有一点都不小进步,从而出现为了依靠有个别 js 中的三个函数,必要加载整个模块,或然为了选取有些 css 中的部分样式信任整个 css,冗余资源相当多
  • 对应涉及不直观未有明了的呼应准绳,导致的一个题目是修改有些业务模块的 css 只怕 js 时,大约只可以依据 grep。靠人来保卫安全页面模块 html、css 和 js 之间的借助关系,轻易犯错,日常出现内容早就去除可是 css 或 js 还设有的主题材料
  • 难于单元测验以页面为最小粒度举办能源整合,不一样作用的职业模块相互影响,复杂度太高,自动化测验难以推进

贰零壹壹 年开首,在应用探究了 FIS、BEM 等方案未来,结合美团开辟框架的莫过于,我们伊始实现了一套轻量级的组件化开辟方案。重要的改良是:

  • 以页面效果组件为单位聚合前端能源
  • 自动加载切合约定的 css、js 能源
  • 将专门的学问数据到渲染数据的调换进度独立出来

图片 19

比喻来讲,美团顶上部分的找寻框就被达成为二个零部件。

图片 20

代码构成:

www/component/smart-box/ ├── smart-box.js # 交互 ├── smart-box.php # 渲染数据生产、组件配置 ├── smart-box.scss # 样式 ├── smart-box.tpl # 内容 └── test ├── default.js # 自动化测验 └── default.php # 单测页面

1
2
3
4
5
6
7
8
www/component/smart-box/
├── smart-box.js    # 交互
├── smart-box.php   # 渲染数据生产、组件配置
├── smart-box.scss  # 样式
├── smart-box.tpl   # 内容
└── test
    ├── default.js  # 自动化测试
    └── default.php # 单测页面

调用组件变得丰裕轻巧:

JavaScript

echo View::useComponent('smart-box', [ 'keyword' => $keyword ]);

1
2
3
echo View::useComponent('smart-box', [
    'keyword' => $keyword
]);

对待以前,能够看看组件化的一些特色:

  • 按需加载只加载要求的前端能源
  • 对应涉及非常明晰组件所急需的前端财富都在平等目录,任务明显且独一,对应提到明显
  • 轻松测验组件是兼备独立表现和互相的纤维单元,可选用 Phantom 等工具自动化测量试验

别的,由于前端财富集中实行调整,组件化也为高阶品质优化提供了空间。比方贯彻组件等第的BigRender、通过数量分析进行能源的联合加载等等。

关键词


基于此前对背景和难点的深入分析,此次做前端的显要正是产生以下3个关键词。

  • 模块化
  • 组件化
  • 工程化

首要明星 seajs 和 handlebars

零件化 2.0:趋于成熟

零件化 1.0 上线后,由于轻便易用,异常的快获得程序猿的确认,并初始在各样事务中采取起来。新的急需络绎不绝,一直再三到 2015 年初,这几个等第大家称为组件化 2.0。上面介绍下第一的多少个革新。

主题材料及对应实施方案


seajs是多个前端模块化js库,功能类似于requirejs,都用来前端js的模块化和按需依附加载的工作。作用都大致,seajs是Tmall玉伯开采的,国产,所以本国使用者比相当多,requirejs国外的,存在时间比seajs要久广大,国外用的可比多。 两个最大的分别在于定义模块的语法分裂,八个是英特尔标准,三个是CMD标准。seajs是CMD标准,所以她的语法更像nodejs,写起来会比requirejs高雅一些。可是短处也比较多,比方相当多第三方库都是比照速龙标准写的,会有宽容性难点,就需求和睦改写模块或许应用spm工具管理。

Lifecycle

组件在高内聚的还要,往往要求暴光一些接口供外界调用,进而能够适应复杂的页面须求,比如提交订单页面须求在开荒密码组件运维完结后绑定提交时的自己谈论。Web Components、React 等都选取了生命周期事件/方法,大家也是一律。

组件的生命周期:

图片 21多个零件的完全生命周期包含:

  • init,起头化组件根节点和安插
  • fetch,加载 css 和 js 资源
  • render,内容渲染,暗中认可的渲染内容措施是 BigRender
  • ready,实行数据绑定等操作
  • update,数据更新
  • destroy,解除所有事件监听,删除全数组件节点

零件提供 pause、resume 方法以福利开展生命周期调整。各样阶段选拔 Promise 串行进行,异步的治本更清楚。使用自定义语义事件,在更换私下认可行为、组件间通讯上充足利用了 YUI 强大的自定义事件体系,有效减弱了支付珍视资金。

举个例证,页面初阶化时组件的启航进度实际上也是依附生命周期实现的:

JavaScript

var afterLoadList = []; Y.all('[data-component]').each(function (node) { var component = new Y.mt.Component(node); // 绑定 init 生命周期事件,在 init 暗许行为达成后履行回调 component.after('init', function (e) { // 即便安顿了延期运营 if (e.config.afterLoad) { // 暂停组件生命周期 e.component.pause(); // 压入延迟运行数组 afterLoadList.push(e.component); } }); // 开首步入生命周期 component.start(); }); Y.on('load', function () { // 在页面 load 事件发生时上涨组件生命周期 afterLoadList.forEach(function (component) { component.resume(); }); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var afterLoadList = [];
Y.all('[data-component]').each(function (node) {
    var component = new Y.mt.Component(node);
    // 绑定 init 生命周期事件,在 init 默认行为完成后执行回调
    component.after('init', function (e) {
        // 如果配置了延迟启动
        if (e.config.afterLoad) {
            // 暂停组件生命周期
            e.component.pause();
            // 压入延迟启动数组
            afterLoadList.push(e.component);
        }
    });
    // 开始进入生命周期
    component.start();
});
 
Y.on('load', function () {
    // 在页面 load 事件发生时恢复组件生命周期
    afterLoadList.forEach(function (component) {
        component.resume();
    });
});

回过头来看,引入生命周期除了带来扩充性外,更要紧的是理顺了组件的一一阶段,有援助越来越好的明白和动用。

主题材料:前后端代码高耦合 全局变量

handlebars是二个前端js模板引擎 笔者在前头的篇章介绍过handlebars及简便的用法,大家能够去看下点我

Data Binding

数码绑定是大家铭心镂骨已久的成效,将 View 和 ViewModel 之间的竞相自动化无疑会省去程序猿的大气时光。在组件化降低关怀点和下跌复杂度后,实现数量绑定变得进一步也许。

我们最终贯彻的数据绑定方案首要参照了 Angular,通过在 html 节点上加多特定的品质证明绑定逻辑,js 扫描这一个内容并举办对应的渲染和事件绑定。当数码爆发变化时,对应的剧情总体重新渲染。

XHTML

<ul class="addressList"> <li mt-bind-repeat="addr in addrList" mt-bind-html="addr.text" > </li> </ul> <script> Y.use(['mt-bind', 'mt-scope'], function () { Y.mt.bind.init(document.body); var scope = Y.one('.addressList').getScope(); // 将 scope.addrList 设置为一个数组,DOM 师长活动渲染其剧情 scope.$set('addrList', [ { text: "first address" }, { text: "second address" } ]); }); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<ul class="addressList">
    <li
        mt-bind-repeat="addr in addrList"
        mt-bind-html="addr.text"
    >
    </li>
</ul>
 
<script>
Y.use(['mt-bind', 'mt-scope'], function () {
    Y.mt.bind.init(document.body);
    var scope = Y.one('.addressList').getScope();
    // 将 scope.addrList 设置为一个数组,DOM 上将自动渲染其内容  
    scope.$set('addrList', [
        { text: "first address" },
        { text: "second address" }
    ]);
});
</script>

使用质量表明绑定逻辑的益处是足以同一时候扶植后端渲染,这对于美团团购这样的偏表现型业务是丰裕要求的,客户能够急迅见到页面内容。

方案:模块化


先是,将前端的公物部分提抽出来,进行模块化编程;
接下来,划定成效域,差异模块间效能域不分享,这样就能够实现,公共代码模块化,幸免了全局变量的苦恼。

此时此刻,流行的模块化编制程序的工具有RequireJS, SeaJS, Webpack,个中SeaJS是由Ali的团队开垦的,在神州有活泼的社区。Webpack由瑞典人编写,体现了更加强的连串工程化特点。
里头,RequireJS和SeaJS分别是英特尔和CMD三种标准的象征。AMD推崇信赖前置,在概念模块的时候将要证明其依据的模块;CMD推崇异步信赖加载的,唯有在运用有些模块的时候再去require。

RequireJS(AMD写法)

SeaJS(CMD写法)

而Webpack则属于集大成者,不仅宽容两个书写标准,况且因选拔异步IO及多元缓存,使Webpack在增量编写翻译上越来越快。但实际上,Webpack在实质上费用中更加的多的是当做编写翻译者和打包者的剧中人物,它构成React一样能够完成模块化开荒,那一个大家在后边突显。

职分1,页面框架配置,seajs起头化

Flux

落到实处多少绑定后,我们不得不面临其他三个问题:如何共同八个零件间的数码。因为某些组件的数额变动,很有比一点都不小可能率引起别的零件的退换。举例当修改购买数码,总金额会扭转,而总金额赶过500 后,还索要显示高额成本提醒。

为了化解这么些主题材料,我们引进了 Flux,使用全局消息总线的思绪展开跨组件交互。

举例因为相互复杂而直接让大家拾分感冒的类型购买页,在运用组件 Flux 重构后,各模块之间的竞相更是清楚:

图片 22

任啥地点方的改良还会有比较多,包涵引进模板引擎 LightnCandy约束模板逻辑、支持组件放肆嵌套、协助异步加载并自行发轫化等。

乘机组件化 2.0 的稳步健全,基本已经得以从容应对日常支付,在作用和质感点面都上了一个台阶。

难题:不佳的品类布局,调节越来越多的意况

新建html页面,引进需求的类库

组件化 3.0:重启征程

光阴的轮子滚滚前行,二零一四 年终,我们相见一些新的时机和挑衅:

  • 依据 Node 的全栈开垦方式初叶选择,前后端渲染有了更多的或许
  • YUI 甘休维护,必要一套新的财富处理方案
  • 新业务不断加多,须求找到一种组件分享的办法,幸免重新造轮子

构成此前的奉行,以致在这里一进程中稳步积淀的对行业内部方案的体味,我们提议了新的组件化方案:

  • 依靠 React 开采页面组件,使用 NPM 实行分发,方便共同建设分享
  • 遵照 Browserify 二回开拓,建设能源打包工具 Reduce,方便浏览器加载
  • 建设适应组件化开采方式的工程化开垦方案 Turbo,方便技术员将零件应用于工作支付中

方案:组件化


组件化建设构造在模块化的基础上,模块化是对财富的保管,组件化是对职业逻辑的管理,各自要有例外的提高动向。经实验切磋,NPM,Webpack(或Browserify)和React的组合会便于大家对品种协会有一个全体的认知。在此个基础上,我们便能十三分有补助地开创一个构造特别清晰的花色。

而针对性不相同组件所享有的每每变动的情景,通过对Flux和Redux的求学和接纳,能够低价我们对此复杂组件状态管理的体制,有越来越的敞亮。(但因为本身到底不是前者,且较懒,关于redux,未做过多读书,间接上手redux-form是为了神速支付管理端表单。)这里要提一下,redux-form十三分苍劲,官方已提交比非常多例子,这里不再熬述。

Flux

Redux

seajs用于做js模块管理,seajs-text能够用于加载handlebars的模版内容

React

在组件化 2.0 的长河中,大家开采大多功力和 React 重合,比如 Data Binding、Lifecycle、前后端渲染,以致一直借鉴的 Flux。除却,React 的函数式编制程序思想、增量更新、宽容性非凡的平地风波种类也让我们极其向往。借着前端全栈开荒的节骨眼,大家初始思考基于 React 进行零部件化 3.0 的建设。

问题:IE8兼容

配置seajs

NPM Reduce

NPM Reduce 构成了大家新的能源管理方案,在那之中:

  • NPM 肩负组件的公布和装置。可以感到是“分”的长河,粒度越小,重用的恐怕性越大
  • Reduce 肩负将页面财富进行打包。可以认为是“合”的长河,让浏览器越来越快地加载

贰个拔尖的零件包:

smart-box/ ├── package.json # 组件包元音讯 ├── smart-box.jsx # React Component ├── smart-box.scss # 样式 └── test └── main.js # 测试

1
2
3
4
5
6
smart-box/
├── package.json    # 组件包元信息
├── smart-box.jsx   # React Component
├── smart-box.scss  # 样式
└── test
    └── main.js     # 测试

NPM 暗许只帮衬 js 文件的管理,我们对 NPM 中的 package.json 举办了增加,扩张了 style 字段,以使打包工具 Reduce 也能够对 css 和 css 中引用的 image、font 实行甄别和拍卖:

XHTML

{ "style": "./smart-box.scss" }

1
2
3
{
    "style": "./smart-box.scss"
}

一经在页面中 require 了 smart-box,经过 Reduce 打包后,js、css 以致图片、字体,都会冒出在浏览器中。

JavaScript

var SmartBox = require('@mtfe/smart-box'); // 页面 var IndexPage = React.createClass({ render: function () { return ( <Header> <SmartBox keyword={ this.props.keyword } /> </Header> ... ); } }); module.exports = IndexPage;

1
2
3
4
5
6
7
8
9
10
11
12
13
var SmartBox = require('@mtfe/smart-box');
// 页面
var IndexPage = React.createClass({
    render: function () {
        return (
            <Header>
                <SmartBox keyword={ this.props.keyword } />
            </Header>
            ...
        );
    }
});
module.exports = IndexPage;

一体化思路和组件化 1.0 一模一样,却又那么分裂。

方案:React(0.14.x)


最一在那早先调研的时候,因为ie包容的忧郁,所以,调查切磋了比较流行的React,Angular,Vue以致小众的Avalon。个中后八个都以MVVM框架(大旨是数据双向绑定)。关于包容,Angular早在1.3本子就放弃了对ie8的支撑,Vue就没计划援救ie8,可面前遭遇中国1/5的ie8客商,只幸好Avalon和React做取舍。

MVVM

Avalon是由去哪里前端架构师“司徒正美”开采的一款基于设想DOM与品质威迫的精美、易用、高品质的前端MVVM框架,适用于各个气象,宽容各类古老刁钻浏览器,吸收最新的技能成果,能相当慢堆砌组件与运用。它以至帮衬到IE6 。

avalon2

包容性和性质好外,弱点就是除了文书档案和十分小的论坛,你搜不到过多的素材,那对中期学习,只怕是别人维护,是特不便利的。何况撰稿人重写了无数js的主干措施,那造成假设出错,除了找小编和融洽改源码外,很可能无处查询。

终极选项React(0.14.x),除了包容外,还应该有诸如社区活泼,财富多,最根本的是有脸书做支撑。当然,它的ie8扶持须要展开多插件配置和支撑,在自己github上关于react学习的有关施行里有连带安顿文件。当中,package.json和webpack.config.js需求优良看下,其次正是注意项目结构(因为用了react-router,项目协会相对清晰),别的宽容相关能够透过上边链接实行学习。
https://github.com/xcatliu/react-ie8
http://www.aliued.com/?p=3240

//basePath由服务端配置域名varbasePath=" seajs 的简要布置seajs.config({base:basePath,alias:{"jquery":"../bower_components/jquery/jquery.seejs.min.js","handlebars":"../bower_components/handlebars/handlebars.seajs.min.js"}});// 加载入口模块seajs.use("./scripts/seajs handlebars.js");````只顾,jquery暗许是不扶持速龙标准,也不扶植seajs,所以这里用的````jquery.seejs.min.js和handlebars.seajs.min.js````都是温馨手动改过的,jquery修改的不二等秘书籍便是在源码中级加上几行代码,如下:````jsdefine(function(){//jquery源代码写在中等return$.noConflict();});

Turbo

一味化解分发和包装的标题还相当不够,业务支出进程倘诺变得繁琐、难以 Debug、质量低下的话,大概不会碰到技术员应接。

为了缓慢解决这一个难题,我们在 Node 框架的底子上,提供了一文山会海中间件和开拓工具,稳步创设对组件友好的前端工程化方案 Turbo。主要有:

  • 支撑前后端同构渲染,让顾客更早见到内容
  • 简化 Flux 流程,数据流越发清晰易维护
  • 引进 ImmutableJS,保险 Store 以外的数量不可变
  • 使用 cursor 机制,保险数据修改/获取同步
  • 支撑 Hot Module Replacement,创新开垦流自动化

由此那么些立异,一线技术员能够一本万利的应用各样零部件,潜心在作业本人上。开荒框架层面的扶持也扭转推进了组件化的发展,我们更乐于使用一多种组件来营造页面效果。

主题材料:前端发送的静态文件(js,css)诉求多

handlebars修改比jquery少了那句return $.noConflict();就可以了。

小结

开掘痛点、剖析调查切磋、应用立异的化解难题思路在组件化开垦施行中不停利用。历经三个大版本的多变,组件化开荒情势有效缓慢解决了专业发展带来的复杂度进步的下压力,并作育程序员具备小而美的工程理念,形成一起创建分享的出色氛围。无可争辩,组件化这种“分而治之”的思辨将会长时间地震慑和拉动前端开荒格局。我们以往已经策画好,接待新的机会和挑衅,用本领的不仅仅与民改进提高程序猿的幸福感。

1 赞 5 收藏 评论

图片 23

方案:Webpack


Webpack帮助转译,打包,压缩等功效。转译能够将react的jsx语言转成js,es6写法转成es5(抢先50%浏览器宽容)等,同一时间,将众多文书的转译结果及正视关系等,打包压缩到三个文本中,只需一次呼吁,便约等于加载了多个文本及其关联,非常的大地进级了前面一个页面加载速度。

basePath能够凭仗实际条件设置。使用alias设置别称后,就能够在sea中使用require()的章程获得到源码

标题:样式供给不高,但重复性高

seajs.use("./scripts/seajs handlebars.js");设置了页面包车型大巴js入口

方案:Ace Admin(ie8)


投机第一依然后端开辟,管理端样式不是温馨研究的第一,故决定选拔模板举办支付。通过调查研商,Ace Admin和AdminLTE都以github上比较受应接的前端样式模板,个中Ace扶持ie8,故选取后面一个用于实际支出。但AdminLTE相对赏心悦目,提供的体裁采取相当多,我们也得以运用。

QQ截图20161027190718.jpg

入口seajs handlebars.js

其三方库


React的想想是由此操作设想dom完毕钦赐职分。可是,在其实支出中,其实有好多有利的轮子并从未React化,依然必要通过外界引进的点子依赖第三方库开展支付。
在那地,React组件的生命周期为引进三方库,提供了componentDidMount等艺术,方便对第三方库开展加载。
此地顺便安利多少个库,如uploadify(flash版上传文件)、ZeroClipboard(点击就能够复制)、dataTables(列表前端组件)

// 全体模块都经过 define 来定义

代码相关


类型代码不太好开源,但前边本身写的多少个react相关的上学例子与类型切合度较高。
此处贴出react学习的例证链接,感兴趣的相爱的人能够活动下载。应接各位互相调换。

define(function(require, exports, module) {

$(function(){

var Handlebars = require('handlebars');

var tpl = require("./data.tpl");

var demoTplc = Handlebars.compile(tpl);

$("body").html( demoTplc("hello world"));

});

});

data.tpl

{ {this} }

加载Handlebars和tpl模板,然后径直调用Handlebars.compile实行模板编写翻译后渲染dom。推行后bady的剧情就改成了hello world。大家能够下载demo,张开seajs handlebars.html看下效果

组件化方案

事先的代码能够成效率seajs动态加载handlebars模板并渲染的意义,但并未完成组件化。未来大家来落实组件的包装。首先创建叁个文书夹,包括

components

- Boxes

-index.js  //js代码管理多少和事件

-index.css //boxes样式

-boxes.tpl //boxes html模板

中间的内容作为demo,小编写的简练一些。

boxes.tpl

this is a boxes!

{ {this} }

index.css

.c-boxes{background-color:red;}.c-boxesh1{color:blue;}

index.js

define(function(require,exports,module){varHandlebars=require('handlebars');varbox={init:function(){returnbox;},clicked:function(){},render:function($dom,data){vartpl=require('./boxes.tpl');vartplc=Handlebars.compile(tpl);// var _clicked = clicked;$dom.html(tplc(data));box.$dom=$dom;$dom.click(function(){box.clicked&&box.clicked();});}};module.exports=box;});

index.js稍微复杂一些,封装了一个目的,并定义了目的的点击事件的表面接口。rander方法使用了前面相似的方法,渲染了bandlerbars模板,并流入点击事件

像这种类型二个组件就曾经封装好了。

零件的使用

前边定义了四个boxes组件,以往我们来使用他.html页面和事先的页面是一律的,独一的区别是入口js换来了componentization.js

componentization.js

define(function(require,exports,module){// 通过 require 引进信任var$=require('jquery');varBoxes=require('boxes');$(function(){//实例化组件varbox=Boxes.init();box.render($("body"),"hello world!");box.clicked=function(){console.log("clicked");};});});

box定义好后,使用起来非常轻易,直接调用box.render()方法就足以了,也顺手个box绑定了点击事件,效果能够看demo中的 componentization.html 页面

组件化其余的思考

组件的沙盘和js都经过seajs加载和打包了,独一可惜的是css需求单独引进。 seajs也可以有css引进的插件sea-css,可是试了一晃没成功。 所以作者的消除方案是使用gulp完结,遍历component下的富有css文件,组合成并压缩成一个css,然后再使用的页面中联合引用这几个统一的css

具体gulp脚本

//css components 组合 营造职分

gulp.task('css-concat', function () {

gulp.src(css_components_Src)

.pipe(concat('allComponent.css'))//合併后的文本名

.pipe(gulp.dest(cssDst));

});

demo

正文示例demo见demo-web

文本的demo在文件夹Handlebars中

选拔方式

Handlebars目录下实行http-server -p 8080

usage.html =》 handlerbars的使用及模板预编写翻译

componentization.html =》 前端开荒框架 - seajs handlebars模块化开拓

错误管理

一旦本地未有http-server命令,存候装nodejs景况,并因而npm安装 http-server 命令:npm install -g http-server

本文由pc28.am发布于前端技术,转载请注明出处:前端开荒框架,前端组件化开采施行

上一篇:UI组件化的一些思想,js长远学习详细深入分析 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • UI组件化的一些思想,js长远学习详细深入分析
    UI组件化的一些思想,js长远学习详细深入分析
    前端 UI组件化的一些思考 2017/04/10 · 基础技术 ·组件化 原文出处: 王一蛋    最近公司推起了共用 UI 组件化的大潮,创建了一个新的 Repo 来放置共用的
  • JavaScript开发工具大全,开发者的
    JavaScript开发工具大全,开发者的
    JavaScript 代码静态品质检查 2015/07/15 · JavaScript·品质检查 原作出处: 百度efe -笔者内江人(@i笔者三亚人)    自鸿蒙初判,Brendan Eich 10天捏出 Mocha 之后
  • 疗养 CSS 的艺术
    疗养 CSS 的艺术
    调试 CSS 的方法 2016/09/06 · CSS ·调试 原稿出处: BenFrain   译文出处:众成翻译 -yanni4night    本人经验过不菲 CSS代码的调解专门的学业,有人家写的也是
  • 何以设置链接样式,CSS结商谈层叠
    何以设置链接样式,CSS结商谈层叠
    如何设置链接样式 2016/09/05 · CSS 本文作者: 伯乐在线 -赖祥燃。未经作者许可,禁止转载! 欢迎加入伯乐在线 专栏作者。 每个合法的文档都会生成一个文
  • CSS图像替换,文本缩进
    CSS图像替换,文本缩进
    CSS图像替换:文本缩进,负边距以及更多方法 2016/07/04 · CSS ·图像替换 原文出处: BaljeetRathi   译文出处:众成翻译    CSS中的图像替换有着广泛而多样