致我们必定组件化的Web,UI组件化的片段思考

前端 UI组件化的一些思想

2017/04/10 · 基础技术 ·
组件化

初稿出处: 王一蛋   

新近店家推起了共用 UI 组件化的大潮,创设了一个新的 Repo 来放置共用的 UI
组件,比如下拉菜单等。出于对历史版本的表单组件的不满,我从两周前发轫踏上了和谐的
React
表单组件制作之路,踩了不少坑也有了成百上千觉醒,之后也会写一篇小说关于本人是何许写这几个组件的(对
React 感兴趣的可以点那里
Hyo
,汉语文档)。之后集团群里分享了这么一个发言视频:Best
Practices on building a UI component library for your company (David
Wells) – FSF
2016
,看完事后感触良多,本文算是该发言内容的一个几乎与探索。

回到正题,如果您在一个特大型团队工作,或者你的营业所有不少机构,你们该如何贯彻全局
UI
组件来跨越各样板块的无尽?想象一个气象,如若您的全体集团都在使用同一段
UI
代码处理公共组件,财务工具在应用它,博客工刘俊相用它,在线聊天工具在选择它,且不论在移动端,桌面端还是web
端都能看出它,那该有多造福?无需累赘而复杂地四回又一回完结效益相近的表单,按钮或是列表。那是一个对峙可以的设置,因为不管你在何处你都只要求爱护一个代码库,且具有全局资源也都在同一个地点,开发者们方可一本万利地找到所需的代码并对其进献。同时,共享
UI
组件同事也会给您的用户带来相容的心得,无论她在浏览或应用哪个工具,移动端或是桌面端,他的所见所感都是相平等的。注意的是同步这一定义,对于具有不少产品的店铺来说如果共享
UI ,那就表示一遍 UI
升级总体集团的出品都会受其影响。这从一大半意义上的话是一件好事,但有时候又会推动许多烦劳,之后会说到。同时您的零件也相应是兼备的,不与任何你所在公司所使用的第三方包相争执。综上,如何陈设你团队产品的
UI
架构,使得其颇具上述优点的同时还有出彩的可扩张性与质量,是大家后天所要啄磨的根本。

在本文中,大家最首要使用 React 作为UI组件化的事例,将页面细分组件化是
React 的着力历史学,我们可以充裕有利的将本文中的理念引入其中。

俺们先来看一个关于 UI 设计指南典型的例子,那是 Salesforce 的 UI 库
Lightning Design
System,他给了非常详尽的
UI
规则,各类产品的页面、组件应当怎么样被处理,非常值得大家学习与借鉴。先来看一个
style guide 应当有些什么内容:

  1. 文档 由你团队成员所写的,要是利用 React 你可以直接通过注释
    Proptypes 的点子,通过 React-docgen 生成文档。
  2. 代码预览
    你应当提供一个足以让开发者实时调试代码的地点,使其他这个零件的使用者可以更好地精晓各种props
  3. 动用实例 提供部分怎么样将其数量导入 UI
    的实例代码,使其余开发者可以更快上手与她们的选取状态。
  4. 相容性
    譬如怎么样利用警告、载入音讯等额外内容的业内,来提供用户相平等的体会。

那么,怎样搭建一个组件库呢?为了酬答这些难题大家可以将其细分为如下多少个小步骤:

  1. 将完整的难题拆开成细目。
  2. 怎么处理 CSS ?
  3. 什么将资源如变量,图标等公有化?
  4. 何以将其包装,便于使用?
  5. 初阶从中得到收入!

首先,大家现讲怎么将标题拆解,大家应有将页面上显得的上上下下看作是组件。也就是说每当你得到设计师的稿子,第一件事应该就是讲页面上任何你所能看到的元素翻译成无数个小组件,那也是
React 的见解:复用组件。

亚洲必赢官网 1

下一步,大家再将小组件组合成为较大的零部件。那里不得不提到 Brad Frost
所指出的 Atomic
Design。它所阐释的见地与本文所要说的见地相似,即由“原子”组成“分子”,“分子”构成“协会”,从而形成模板,进而生成页面。看下那个事例,标签,输入,按钮各是一个“原子”,合在一起即成了一个“分子”。

亚洲必赢官网 2亚洲必赢官网 3

其次, CSS
平昔以来都是一个非常讨厌的标题。大家理应如何处理类名争持?怎么着行使第三方库的
CSS 文件?怎样有限支持与 CSS
文件不顶牛?如何确保相互独立?对于这个题材现在曾经有了不少解决方案。

大卫 韦尔斯 在发言中涉嫌的与大家公司今天所采纳的都是通过 PostCSS + CSS
modules的化解方案。关于 CSS Modules 搭配 React
的用法,那里有个很好的事例:Modular CSS with
React
。具体来说可以见此用例:

JavaScript

/* Thumbnail.jsx */ import styles from ‘./Thumbnail.css’; render() {
return (<img className={styles.image}/>) }

1
2
3
4
5
/* Thumbnail.jsx */
import styles from ‘./Thumbnail.css’;
render() {
  return (<img className={styles.image}/>)
}

JavaScript

/* Thumbnail.css */ .image { border-radius: 3px; }

1
2
3
4
/* Thumbnail.css */
.image {
  border-radius: 3px;
}

Hash 后转移的 HTML tag 与 CSS 看起来会是那般:

JavaScript

/* Rendered DOM */ <img class=”Thumbnail__image___1DA66″/>

1
2
/* Rendered DOM */
<img class="Thumbnail__image___1DA66"/>

JavaScript

/* Processed Thumbnail.css */ .Thumbnail__image___1DA66 {
border-radius: 3px; }

1
2
3
4
/* Processed Thumbnail.css */
.Thumbnail__image___1DA66 {
  border-radius: 3px;
}

此地将在我们 Thumbnail.jsx 文件中通过 CSS modules 引入 CSS
文件,再经过引入的 style 变量获取 hash 后的 CSS 类名。

此地提到的另一个工具 PostCSS
会将您的css文件全加上前缀名以适应不一样浏览器,解决 CSS 4 的包容性难题。

从而你真正要求运用 PostCSS 和 CSS Modules
么?你可以问自己如下难点:你在一个团队中工作么?你采用第三方库的 CSS
文件么?你的成品在第三方环境中运行么?你想要你的制品在其余条件中感受一致么?假使你答应是,那您可以挑选尝试这一方案,因为这一化解方案基本缓解了类名争辨与浏览器包容的题材。

第三,关于什么处理共享资源。对于全局变量与 mixin ,我们提议通过多少个PostCSS
的插件来解决,而非使用sass等预处理器语言。可以因而一个简练的Postcss
config来解释:

JavaScript

var vars = require(‘postcss-simple-vars’); var mixins =
require(‘postcss-mixins’); var postCSSConfig = [ mixins({ mixins:
require(‘./mixins’) }), vars({ variables: require(‘./variables’) }), ]

1
2
3
4
5
6
7
var vars   = require(‘postcss-simple-vars’);
var mixins   = require(‘postcss-mixins’);
 
var postCSSConfig = [
  mixins({ mixins: require(‘./mixins’) }),
  vars({ variables: require(‘./variables’) }),
]

此地我们从一个 mixins.js 文件中提取全局mixin,一个 varibles.js
文件中领到全局变量,他将会在你具备通过 PostCSS 编译的 CSS
文件中生效。实际运用中与less和sass极度相似,见例:

JavaScript

.hyo { @mixin MarsPower; /* 在 mixin.js 文件中定义 */ color: $MarsRed;
/* 在 variables.js 文件中定义 */ }

1
2
3
4
.hyo {
  @mixin MarsPower; /* 在 mixin.js 文件中定义 */
  color: $MarsRed; /* 在 variables.js 文件中定义 */
}

对于图标,由于其轻量型与便利性大家一般接纳svg。基本的行事流程是由设计师创设 svg ,在您的 JS 代码中引入 svg ,通过
’webpack-svgstore-plugin’ 优化 svg 并生成 sprite ,将 sprite 注入 DOM
。此处大家可以利用 svg use 标签,方式如:

XHTML

<svg><use id=“icon-aaa”></svg>

1
<svg><use id=“icon-aaa”></svg>

第四步,也是最后一步,大家应当怎么样搭建以及包装?

先是,我们有卓殊多的工具来驱动开发 React
组件变得令人心思愉悦,推荐多少个常用的第三方库:
carte-blanche
那是个越发牛b的 React 开发工具,只需简单几步就可已在浏览器中测试你的
React 组件,同时还协助随机生成 prop 来测试你的零件会不会应为 prop
格外而夭亡。
react-storybook 那是一个 carte-blanche
相当相像的抉择,也是自个儿用来支付
Hyo
的工具。
react-docgen
文档生成工具,你可以直接导入一个react文件夹,若是您在proptype中谢了诠释它将会自动为你转移文档。

在本子更新时,注意使用语义化版本。每当你要从头写一个新的组建时,可以先在
Github 上探寻一下先行者的落到实处格局,站在巨人的双肩上干活才会一石二鸟。

说到底,关于怎么着打包,DW 推荐的格局是之类文件结构:

亚洲必赢官网 4

对此我表示很赞成。分开打包每个小的零件入口,扁平化你的文本结构,组件之间可以相互依赖使用,对于开发成效与扩充化能力相当有赞助。

稍许时候很难去查看你在哪个页面使用了哪个组件。那里您可以运用一个监视器组件来查询你选拔的零件。那在无数时候极度方便,譬如你想进步某一个组件,你会想去精通怎么页面或是组件依赖了这几个组件从而举行改动,DW
提供了一个贯彻,我们可以依照我们的急需来完毕自己的 Monitor Component。

亚洲必赢官网 5

说到底的末段,小结几个开发 React 组件中常遇见的标题。(至少我是碰见了-
-)首先,做事先想清楚要落实的
Feature,与设计师探究并写下团结的须求,市面上是不是有可用的替代品,尽可能不要定义过多的
prop,不然在事后维护会非凡麻烦。其次,尽可能地予以使用者客制化的职务,譬如内容什么渲染,排序怎么样进行等,最好开放一个
api
使得使用者能够协调定义,因为你永远不能够估摸并知足所有使用者的必要。第三,在富有浏览器上拓展测试,老生常谈了但有时候依旧会忘。最终,从开始便定义好
lint 的平整并服从它,可以参考
AirBnB
的安顿作为初步点。

滔滔不竭写了那般多,希望大家都能从中能收获些许。最终再安利一下
Hyo,也好不不难和谐的首先个认真做的开源项目,希望大家多多点星!
|
Demo点这里
|
文档点那里
|

1 赞 1 收藏
评论

亚洲必赢官网 6

让CSS更完美:PostCSS-modules

2017/01/22 · CSS致我们必定组件化的Web,UI组件化的片段思考。 ·
POSTCSS

原稿出处: Alexander
Madyankin   译文出处:众成翻译   

译者注(GeoffZhu):
那篇适合部分利用过预处理CSS的开发者,比如less,sass或stylus,如若你都没用过,那您肯定不是个好司机。在PostCSS中曾经可以选用CSS
Modules了,该篇小编进献了一个新工具,可以让越来越多开发者方便的应用最新的CSS
Modules。

大家和大局成效域的css斗争了多年,现在好不简单是时候甘休它了。不管您用的是怎么着语言仍旧框架,CSS命名争辩将不再是个难点。我将给你体现一下PostCSS和PostCSS-modules哪些行使,并且可以在服务端使用它们。
CSS起头只是一个吹嘘文档的工具,不过事情到1996年暴发了转变。浏览器中不再单纯唯有文档了,即时通信,各个软件,游戏,没什么是浏览器不可以承载的。

近日,大家在HTML和CSS方面曾经走了很远很远,开发者们振奋出了CSS所有的潜力,甚至创办出了部分CSS本身都快精晓不了的事物。

每一个有经历的开发者都精晓 —
每一回使用全局命名空间都是留住了一个发出bug的隐患,因为火速就可能出现类似命名争论之类的标题,再加上其余地点(项目尤为大等)的震慑,代码越来越不易维护。

对此CSS来说,那意味着有标题标布局。CSS特异性和CSS宽泛性之间,一贯留存着如史诗般的对决。仅仅是因为各类接纳器都可能会潜移默化到那么些不想被影响的要素,使之爆发了冲突。

主导所有编程语言都支持部分成效域。和CSS朝夕相伴的JavaScript有速龙,
CommonJS和终极确定的ES6 modules。然而我们并从未一个可以模块化CSS的方式。

对此一个高品质种类以来,独立的UI组件(也就是组件化)非凡关键的 —
每个组件小巧独立,可以拼合成复杂的页面,那让大家节省了无数的办事。可是大家一味有一个难题,怎样预防全局命名争论那?

致大家一定组件化的Web

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

初稿出处:
AlloyTeam   

那篇小说将从两年前的五回技术争议起来。争论的聚焦就是下图的三个目录分层结构。我说按模块划分好,他说您傻逼啊,当然是按资源划分。

亚洲必赢官网 7 《=》亚洲必赢官网 8

”按模块划分“目录结构,把目前模块下的具备逻辑和资源都放一块了,那对于多人独自开发和护卫个人模块不是很好呢?当然了,那争论的结果是自个儿宝宝地改回主流的”按资源划分“的目录结构。因为,没有做到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

方法之间线性跳转,你大约也能感受那样代码弊端。随着页面逻辑更是复杂,那条”进程线“也会尤其长,并且尤其绕。加之缺乏专业约束,其余项目成员依照各自须要,在”进度线“加插各自逻辑,最后这一个页面的逻辑变得难以有限辅助。

亚洲必赢官网 9

开发要求小心,生怕影响“进度线”前面正常逻辑。并且每四回加插或涂改都是bug泛滥,无不令产品有关人员一律提心吊胆。

 页面结构模块化

据悉下边的面向进程的题材,行业内也有成百上千解决方案,而我辈团队也总计出一套成熟的缓解方案:Abstractjs,页面结构模块化。大家得以把我们的页面想象为一个乐高机器人,须要分歧零件组装,如下图,如果页面划分为tabContainer,listContainer和imgsContainer多个模块。最后把那几个模块add到终极的pageModel里面,最后选取rock方法让页面启动起来。

亚洲必赢官网 10
(原经过线示例图)

亚洲必赢官网 11
(页面结构化示例图)

上边是伪代码的贯彻

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”感到失望亚洲必赢官网 12,依然“太好了是react+webpack”不用再学四遍新框架的心满意足亚洲必赢官网 13。无论如何下面的始末不会让您失望的。

一,组件生命周期

亚洲必赢官网 14

React天生就是强制性组件化的,所以能够从根本性上化解面向进程代码所带来的分神。React组件自身有生命周期方法,可以知足“接口规范化”能力点。并且跟“页面结构模块化”的所封装抽离的多少个章程能挨个对应。其余react的jsx自带模板效率,把html页面片直接写在render方法内,组件内聚性尤其紧凑。

是因为React编写的JSX是会先生成虚拟Dom的,要求时机才真的插入到Dom树。使用React必必要明了组件的生命周期,其生命周期多个情形:

Mount: 插入Dom

Update: 更新Dom

Unmount: 拔出Dom

mount那单词翻译扩展,嵌入等。我倒是提议“插入”更好领悟。插入!拔出!插入!拔出!默念三次,懂了没?别少看黄段子的力量,

亚洲必赢官网 15

组件状态就是: 插入-> 更新 ->拔出。

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

componentWillMount()  准备插入前

componentDidlMount()  插入后

componentWillUpdate() 准备更新前

componentDidUpdate()  更新后

componentWillUnmount() 准备拔出前

因为拔出后为主都是贤者形态(我说的是组件),所以没有DidUnmount那几个方式。

除此以外React其它一个骨干:数据模型props和state,对应着也有自个状态方法

getInitialState()     获取早先化state。

getDefaultProps() 获取默认props。对于那多少个从没父组件传递的props,通过该方法设置默许的props

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

再有一个尤其情状的处理函数,用于优化处理

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

添加最重大的render方法,React自身带的章程刚刚好10个。对于初学者的话是相比较为难消化。但实质上getInitialStatecomponentDidMountrender多少个情状方法都能成功大多数组件,不必惧怕。

回来组件化的宗旨。

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

亚洲必赢官网 16

咱俩换算成React生命周期方法:

亚洲必赢官网 17

 

组件的情形方法流中,有两点需求十分表明:

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写的代码依旧很丑。

亚洲必赢官网 18
(即便用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内聚

“功能域独立”—— (50%)  js的成效域独立

“自定义标签”—— (100%)jsx

“可互相结合”—— (50%)  可整合,但缺乏使得的加载格局

“接口规范化”—— (100%)组件生命周期方法

 

Webpack 资源组件化

对此组件化的资源独立性,一般的模块加载工具和构建流程视乎变得吃力。组件化的构建工程化,不再是事先大家广大的,css合二,js合三,而是体验在组件间的依赖于加载关系。webpack正好契合须要点,一方面填补组件化能力点,另一方辅助我们周全组件化的完整营造环境。

率先要说美素佳儿点是,webpack是一个模块加载打包工具,用于管理你的模块资源信赖打包难点。那跟大家熟练的requirejs模块加载工具,和grunt/gulp营造工具的定义,多多少少有些出入又有点雷同。

亚洲必赢官网 19

率先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{\r\n position: relative;\r\n
width: 100%;\r\n margin: 50px;\r\n background:
#fff;\r\n}\r\n\r\n.slider-wrap li{\r\n text-align:
center;\r\n line-height: 20px;\r\n}”, “”]); /***/ }, /* 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{\r\n position: relative;\r\n width: 100%;\r\n margin: 50px;\r\n background: #fff;\r\n}\r\n\r\n.slider-wrap li{\r\n text-align: center;\r\n line-height: 20px;\r\n}", ""]);
 
/***/ },
/* 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的模块加载器之后,大家组件的加载难题,内聚难题也都事业有成地解决掉

“资源高内聚”—— (100%) 所有资源得以一js出口

“可互相结合”—— (100%)  可组成可依靠加载

 

 CSS模块化实践

很快乐,你能翻阅到这边。近年来大家的零件完毕度极度的高,资源内聚,易于组合,功能域独立互不污染。。。。等等亚洲必赢官网 20,视乎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年的7-Up,好好庆祝一下。不是吗?

亚洲必赢官网 21

 

 组件化之路还在此起彼伏

webpack和react还有许多新万分首要的特点和职能,介于本文仅仅围绕着组件化的为主干,没有各样演讲。别的,配搭gulp/grunt补充webpack创设能力,webpack的codeSplitting,react的零部件通讯难点,开发与生育环境安排等等,都是百分之百大型项目方案的所不可不的,限于篇幅难点。可以等等我更新下篇,或大家可以活动查阅。

然而,不得不再安利一下react-hotloader神器。热加载的支出形式相对是下一代前端开发必备。严酷说,一旦没有了热加载,我会很泼辣地舍弃那套方案,即便那套方案再怎么完美,我都讨厌react须求5~6s的编译时间。可是hotloader可以在自家不刷新页面的景况下,动态修改代码,而且不单单是样式,连逻辑也是即时生效。

亚洲必赢官网 22

如上在form表单内。使用热加载,表单不须要重新填写,修改submit的逻辑立即见效。那样的付出功能真不是增高仅仅一个品位。必须安利一下。

 

想必你发觉,使用组件化方案将来,整个技术栈都被更新了一番。学习花费也不少,并且可以预言到,基于组件化的前端还会比比皆是相差的标题,例如品质优化方案要求再行考虑,甚至最中央的零件可复用性不自然高。前边很长一段时间,要求我们不住磨砺与优化,探求最优的前端组件化之道。

最少我们可以想象,不再担心自己写的代码跟某个什么人何人争执,不再为找某段逻辑在三个文件和措施间不停,不再copy一片片逻辑然后改改。大家每便编写都是可拔取,可结合,独立且内聚的机件。而各种页面将会由一个个嵌套组合的零件,相互独立却相互效能。

 

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

至此,感谢你的阅读。

1 赞 6 收藏 1
评论

亚洲必赢官网 23

React.js深刻学习详细分析

2016/07/16 · JavaScript
· ReactJS

正文作者: 伯乐在线 –
winty
。未经作者许可,禁止转发!
迎接参预伯乐在线 专辑小编。

后天,继续浓厚学习react.js。

目录:

一、JSX介绍

二、React组件生命周期详解

三、属性、状态的意义和用法

四、React中事件的用法

五、组件的协同使用

六、React中的双向绑定

 一、JSX介绍

①定义

JSX=JavaScript
XML,是一种在React组件内部打造标签的类XML语法。React在不行使JSX的意况下一致可以干活,不过使用JSX可以提升组件的可读性,增强JS语义,结构清晰,抽象程度高,代码模块化。由此推荐在React中选用JSX。

②特点

1、元素名首字母大写

2、符合嵌套规则

3、可以写入求值表明式

4、驼峰式命名

5、无法应用javascript原生函数的有些首要词,如for和class。要求替换成htmlFor和className

③施用办法

1、使用动态值:JSX将三个花括号之间的内容{…}渲染为动态值,花括号指明了一个javascript上下文环境,花括号内部可以是一个变量,也足以是函数。 例如:

JavaScript

var name=“winty”; <p>{name}</p>

1
2
3
var name=“winty”;
 
<p>{name}</p>

JavaScript

function date(d){ return [ d.getFullYear(), d.getMonth()+1, d.getDate()
].join(‘-); }; <p>{date(new Date()}</p>

1
2
3
4
5
6
7
8
function date(d){
  return [
    d.getFullYear(),
    d.getMonth()+1,
    d.getDate()
  ].join(‘-);
};
<p>{date(new Date()}</p>

2.注释:第一,在子节点中注释要用大括号包裹起来,然后就足以单行注释/**/,也可以多行注释//。

JavaScript

var Hello=React.createClass({ render:function(){ return <p
name=”winty”> //set name Hello ,World /* 多行注释 多行注释 */
</p> } });

1
2
3
4
5
6
7
8
9
10
11
var Hello=React.createClass({
     render:function(){
         return <p name="winty"> //set name
                  Hello ,World
                  /*
                    多行注释
                    多行注释
                  */
                  </p>
           }
   });

3.采取CSS内联样式

JavaScript

var style={ color:#000; }; React.render(<div
style={style}>….</div>,document.body);

1
2
3
4
var style={
    color:#000;
};
React.render(<div style={style}>….</div>,document.body);

4.运用口径判断

JavaScript

//方法1,三目运算符 var Hello=React.createClass({ render:function(){
return <p>Hello,{this.props.name?this.props.name :
“LuckyWinty”}</p> } }); //方法2,if-else语句 var
Hello1=React.createClass({ getName:function(){ if(this.props.name)
return this.props.name; else return “LuckyWinty”; render:function(){
return <p>Hello,{this.getName}</p> } });
//方法3,使用逻辑||运算符 var Hello3=React.createClass({
render:function(){ return
<p>Hello,{this.props.name||”LuckyWinty”}</p> } });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//方法1,三目运算符
var Hello=React.createClass({
     render:function(){
        return <p>Hello,{this.props.name?this.props.name : "LuckyWinty"}</p>
     }
});
 
//方法2,if-else语句
var Hello1=React.createClass({
     getName:function(){
          if(this.props.name)
            return this.props.name;
          else
            return "LuckyWinty";
     render:function(){
        return <p>Hello,{this.getName}</p>
     }
});
//方法3,使用逻辑||运算符
var Hello3=React.createClass({
     render:function(){
        return <p>Hello,{this.props.name||"LuckyWinty"}</p>
     }
});

④非DOM属性介绍

JSX中有3个非DOM属性,分别是:dangerouslySetInnerHTML、ref、key。

dangerouslySetInnerHTML:在JSX中间接插入HTML代码,可是只要能幸免选用那一个特性则尽量幸免使用。

老式的使用 innerHTML 可能会促成 cross-site scripting
(XSS) 攻击。
净化用户的输入来浮现的时候,平时会产出错误,不合适的清洁也是导致网页攻击 的原委之一。

在绝望的了然安全题材后果并正确地净化数据之后,生成只包蕴唯一
key __html 的目的,并且对象的值是整洁后的数码。例如:

JavaScript

function createMarkup() { return {__html: ‘First · Second’}; };
<div dangerouslySetInnerHTML={createMarkup()} />

1
2
3
4
function createMarkup() {
  return {__html: ‘First &middot; Second’};
};
<div dangerouslySetInnerHTML={createMarkup()} />

ref:父组件引用子组件,你可以通过在品质中安装期望的引用名来定义一个引用。例如:

JavaScript

… render:function(){ return <div> <input ref=”MyInput”
…/> </div> } …
//然后您就足以在组件中的任哪儿方拔取this.refs.myInput获取那么些引用了

1
2
3
4
5
6
7
8
render:function(){
  return <div>
           <input ref="MyInput" …/>
           </div>
}
//然后你就可以在组件中的任何地方使用this.refs.myInput获取这个引用了

key:是一个可选的绝无仅有标识符,通过给组件设置一个独一无二的键,并确保它在一个渲染周期中保持一致,使得React可以更只好地控制应该录取一个组件如故销毁一碗水端平建一个零部件,进而升高渲染质量。例如:

JavaScript

var Hello3=React.createClass({ render:function(){ return <ul>
<li key=”1″>1</li> <li key=”2″>2</li> <li
key=”3″>3</li> </ul> } });

1
2
3
4
5
6
7
8
9
var Hello3=React.createClass({
     render:function(){
        return <ul>
                <li key="1">1</li>
                <li key="2">2</li>
                <li key="3">3</li>
         </ul>
     }
});

更多详细新闻请参见:

 

二、React组件生命周期详解

组件本质上就是状态机,输入确定,输出一定确定。状态和结果一一对应,从而使程序变得直观。状态发生转移时会触发差距的钩子函数,从而让开发者有时机做出响应。可以用事件的笔触来通晓状态,可是事件与事件时期交互独立,不过差距景色之间可能会互相影响。

零件的拥有意况结合起来就成了组件的生命周期。即:开头化阶段->运行中阶段->销毁阶段。

不等生命周期内足以自定义的函数

初步化阶段:

①getDefaultProps:获取默许属性,只调用一回,是在createClass之后调用的。实例之间共享引用

②getInitialState:伊始化每个实例的有意初步化状态

③component威尔Mount:mout就是装载的意味,那些主意的意思乃是组件即将被装载到页面中,也是render从前最终一回修改情状的机会

④render:组件在render函数生成虚拟节点,最终由react将虚拟节点变成真的的节点渲染到页面上。只好访问this.props和this.state,唯有一个顶层组件,最好不用改动意况和DOM输出。

⑤componentDidMount:组件被装载后才会被调用,也就是说调用这么些点子的时候,组件已经被渲染到了页面上,那几个时候可以修改DOM

那多个函数的实施种种就是从上到下的。须要小心的是getDefaultProps只会在组件的首先个实例被初阶化的时候被调用,也就是说第三个实例之后都是从getInitialState开端调用。同一个零部件的具备实例的默许属性都是同等的。

重中之重测试代码:

JavaScript

<script type=”text/babel”> var Hello=React.createClass({
getDefaultProps:function(){ console.log(“getDefaultProps, 1”); },
getInitialState:function(){ console.log(“getInitialState, 2”); return
null; }, componentWillMount:function(){ console.log(“componentWillMount,
3”); }, render:function(){ console.log(“render, 4”); return
<p>Hi,LuckyWinty!</p> }, componentDidMount:function(){
console.log(“componentDidMount, 5”); }, });
React.render(<Hello></Hello>,document.body); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script type="text/babel">
    var Hello=React.createClass({
      getDefaultProps:function(){
          console.log("getDefaultProps, 1");
      },
      getInitialState:function(){
          console.log("getInitialState, 2");
          return null;
      },
      componentWillMount:function(){
          console.log("componentWillMount, 3");
      },
      render:function(){
          console.log("render, 4");
          return <p>Hi,LuckyWinty!</p>
      },
      componentDidMount:function(){
          console.log("componentDidMount, 5");
      },
    });
    React.render(<Hello></Hello>,document.body);
</script>

运行结果:

亚洲必赢官网 24

运转中阶段:

①component威尔ReceiveProps:那么些函数在组件即将接受到属性时接触的,或者是父组件的性质暴发变化时,属性在传递到零部件此前,开发者有机遇通过那个函数去处理属性。比如修改,更新内部情形等。

②shouldComponentUpdate:当组件接收到新属性或者新图景的时候接触的。那一个是一个疑团函数,也就是说大家可以告诉react不去革新某个组件。因为有时候属性或者状态并不会促成组件爆发更新。在组件不要求立异的情景下,手动使shouldComponentUpdate重返false,那样react就不必要再经过render和diff算法去判断是不是要翻新,从而升高品质。

③component威尔Update:render触发以前接触,更新组件,不可能改改属性和气象

④render:组件在render函数生成虚拟节点,最终由react将虚拟节点变成真的的节点渲染到页面上,只好访问this.props和this.state,唯有一个顶层组件,最好不要涂改意况和DOM输出。

⑤componentDidUpdate:render之后,真正的DOM被渲染之后调用

亚洲必赢官网,备注:那多个函数的推行各样也是从上到下的。这些的测试代码已上传至:

销毁阶段:

①component威尔Unmount:那几个函数在销毁操作真正实施从前调用,给开发者最终的空子进行部分清理工作。

三、属性、状态的意义和用法

品质的含义:

props=properties,属性是不得以由组件自己举办修改的,组件的特性是由父组件传递进入的。

特性的用法:

一、键值对

XHTML

<Hello name=”winty”/> 字符串 <Hello name={123}/>
大括号包裹的求值说明式 <Hello name={[1,2,3]}/> 传入数组
<Hello name={winty}/> 变量

1
2
3
4
<Hello name="winty"/>   字符串
<Hello name={123}/>    大括号包裹的求值表达式
<Hello name={[1,2,3]}/>   传入数组
<Hello name={winty}/>   变量

二、展开定义(个人认为就是对象式定义)

JavaScript

var props={ one:”123″, two:”22″ }

1
2
3
4
var props={
   one:"123",
   two:"22"
}

如此那般定义的话,理论上采用相应是one={props.one}那样调用,但是这么写起来相比麻烦,而且纵然数量被改动,就必要相应修改相应的赋值,并且无法动态地安装属性,所以react中添加了一种展开语法:

<Hello {…props}/>    //也就是多少个点加上对象名称。

如此使用进行语法,react就会活动把目的中的变量和值当作是性质的赋值,所以Hello实际上就获得了one、two多少个特性,若是没有多个点的话,Hello获得的莫过于就是props对象,使用的时候还索要团结从中取出变量和值

三、调用react提供的setProps()函数(大概不用)

JavaScript

var
instance=React.render(<HelloWorld></HelloWorld>,document.body);
instance.setProps({name:”winty”});

1
2
var instance=React.render(<HelloWorld></HelloWorld>,document.body);
instance.setProps({name:"winty"});

动静的意思:

state,状态是由事物自行处理、不断变化的

情景的用法:

getInitialState:开始化实例的景色

setState:更新组件状态,一旦更新了情景,那么就会触发diff算法,检查内容是还是不是暴发变化,若有变动则更新组件,否则就不要。

质量和景色相比

相似点:都是纯JS对象、都会触发render更新、都抱有明确。

亚洲必赢官网 25

质量和景色区分:组件在运转时须求修改的数码就是气象

四、React中事件的用法

事件处理函数:React绑定事件处理器的办法和HTML语法万分接近,所有的轩然大波在命名上与原生的javascript规范一致,并且会在同等的情况下接触。

编排函数

handleClick:function(){

}

绑定

onClick={this.handleClick}

种种事件详细表明:

①平移装备上的触摸事件:onTouchCancel、onTouchEnd、onTouchMove、onTouchStart

②键盘类事件:onKeyDown、onKeyPress、onKeyUp

③剪切类事件:onCopy、onCut、onPaste

④表单类:onChange//内容变更即触发、onInput//输入框、onSubmit//禁止表单默认跳转行为

⑤事件:onFocus、onBlur

⑥UI元素类:onScroll

⑦鼠标滚动事件:onWheel

⑧鼠标类型:onClick、onContextMenu//右键菜单、onDoubleClick
//双击、onMouseDown、onMouseEnter、onMouseLeave、onMouseMove、onMouseOut、onMouseOver、onMouseUp

⑨拖拽事件:onDrop、onDrag、onDragEnd、onDragEnter、onDragExit、onDragLeave、onDragOver、onDragStart

事件目标介绍

应用办法:纵使在编排事件目的处理函数的时候,添加一个参数。获得这么些目的之后,就经过对象的性质来可以收获一些新闻。

例如:

JavaScript

handleChange:function(event){ console.log(event.target.value); }

1
2
3
handleChange:function(event){
    console.log(event.target.value);
}

以身作则中,event就是事件目的,event.target就是事件目的的性质,就是呼应的DOM元素,获得那个元素之后再得到它的值。

事件目的属性

通用属性:

亚洲必赢官网 26

其余不一致类其他风云有两样的质量,不难询问一下

亚洲必赢官网 27

略知一二了轩然大波的部分性质,大家就足以很有益地在React中获得那些属性,进行一些逻辑的处理,完成部分繁杂的事务成效、页面效果等。

比如:我们得以使用鼠标事件性质,实时突显鼠标在某个区域的坐标:

JavaScript

<script type=”text/jsx”> var HelloWorld = React.createClass({
getInitialState: function () { return { x: 0, y: 0 } }, handleMouseMove:
function (event) { this.setState({ x: event.clientX, y: event.clientY
}); }, render: function () { return <div
onMouseMove={this.handleMouseMove} style={{ height: ‘500px’, width:
‘500px’, backgroundColor: ‘gray’ }}> {this.state.x + ‘, ‘ +
this.state.y} </div>; }, });
React.render(<HelloWorld></HelloWorld>, document.body);
</script>

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
<script type="text/jsx">
        var HelloWorld = React.createClass({
            getInitialState: function () {
                return {
                    x: 0,
                    y: 0
                }
            },
            handleMouseMove: function (event) {
                this.setState({
                    x: event.clientX,
                    y: event.clientY
                });
            },
            render: function () {
                return <div onMouseMove={this.handleMouseMove} style={{
                    height: ‘500px’,
                    width: ‘500px’,
                    backgroundColor: ‘gray’
                }}>
                {this.state.x + ‘, ‘ + this.state.y}
                </div>;
            },
        });
        React.render(<HelloWorld></HelloWorld>, document.body);
    </script>

五、组件的共同应用

组件协同应用的概念:组件的一块儿本质上就是对组件的一种集体、管理格局。

组件协同应用的目标:逻辑清晰、代码模块化、封装细节、代码可复用。

零件协同使用的办法:

①零部件嵌套使用:也就是说,用一个父组件把子组件封装起来,本质就是父子关系。如下图描述:

亚洲必赢官网 28

实例代码:

JavaScript

var React = require(‘react’); var
CommentList=require(‘./CommentList.jsx’); var
CommentForm=require(‘./commentFrom.jsx’); var CommentBox =
React.createClass({ render: function() { return ( <div
className=”commentBox”> <h1>Comments</h1> <CommentList
/> //那是一个零件 <CommentForm /> //那是另一个组件 </div>
); } }); module.exports = CommentBox;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var React = require(‘react’);
var CommentList=require(‘./CommentList.jsx’);
var CommentForm=require(‘./commentFrom.jsx’);
 
var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList />   //这是一个组件
        <CommentForm />    //这是另一个组件
      </div>
    );
  }
});
 
module.exports = CommentBox;

父子组件之间的通讯:

父组件->子组件:通过品质,父组件把数量通过质量来传递给子组件

子组件->父组件:本质上,子组件不可能向父组件通讯。不过足以直接地通过接触事件来通信,也就是委托。

嵌套组合缺点:

父子关系的现实落到实处内需经过沉思熟虑,贸然编写将导致关系混乱、代码难以维护

无法控制所有细节,使用者只晓得组件用法,不精通达成细节,遇到题目难以修复

②Mixin:也就是足以把相同的代码抽象出来,封装成一个函数,然后再调用。

Mixin的目的:横向抽离出组件的形似代码

一般概念:面向切向面编程、插件

实例代码:

JavaScript

var Time=React.createClass({ mixins:[IntervalMixin(1000)],
getInitialState:function(){ return {secondElapsed:0}; },
onTick:function(){
this.setState({secondElapsed:this.state.secondElapsed+1}); },
render:function(){ return ( <div>Seconds
Elapsed:{this.state.secondsElapsed}</div> ); } });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var Time=React.createClass({
    mixins:[IntervalMixin(1000)],
    getInitialState:function(){
       return {secondElapsed:0};
    },
    onTick:function(){
    this.setState({secondElapsed:this.state.secondElapsed+1});
    },
    render:function(){
    return (
       <div>Seconds Elapsed:{this.state.secondsElapsed}</div>
    );
    }
});

mixin极度不难,它们就是鱼目混珠进组件类中的对象而已。React在那上头达成得更加力透纸背,它能预防静默函数覆盖,同时还支持四个mixin混合。然则这几个效用在其余系统中或者引起冲突。例如:

JavaScript

React.createClass({ mixins:[{ getInitialState:function(){ return {a:1}}
}], getInitialState:function(){ return {b:2}} });

1
2
3
4
5
6
React.createClass({
    mixins:[{
      getInitialState:function(){  return {a:1}}
    }],
    getInitialState:function(){  return {b:2}}
});

这么在mixin和零部件类中还要定义了getInitialState方法,获得的最先state是{a:1,b:2}.如若mixin中的方法和组件类中的方法再次来到的目的中留存双重的键,React会抛出一个漏洞相当多来警告那么些题材。

 六、React中的双向绑定

React创建的见解跟angular那多少个框架就是不一样的,React是单向数据绑定的。那么怎么落实像angular那样的双向绑定效果呢?看代码:

XHTML

<!DOCTYPE html> <html lang=”zh-cn”> <head> <meta
charset=”UTF-8″> <title>React中的双向数据绑定</title>
</head> <body> <script
src=”./react-0.13.2/react-0.13.2/build/react-with-addons.js”></script>
<script
src=”./react-0.13.2/react-0.13.2/build/JSXTransformer.js”></script>
<script type=”text/jsx”> var BindingMixin = { handleChange:
function(key) { var that = this var newState = {} return function(event)
{ newState[key] = event.target.value that.setState(newState) } } } var
BindingExample = React.createClass({ mixins:
[React.addons.LinkedStateMixin], getInitialState: function() { return
{ text: ”, comment: ”, } }, render: function() { return <div>
<input type=”text” placeholder=”请输入内容”
valueLink={this.linkState(‘text’)} /> <textarea
valueLink={this.linkState(‘comment’)}></textarea>
<h3>{this.state.text}</h3>
<h3>{this.state.comment}</h3> </div> } })
React.render(<BindingExample></BindingExample>,
document.body); </script> </body> </html>

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
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>React中的双向数据绑定</title>
</head>
<body>
    <script src="./react-0.13.2/react-0.13.2/build/react-with-addons.js"></script>
    <script src="./react-0.13.2/react-0.13.2/build/JSXTransformer.js"></script>
    <script type="text/jsx">
        var BindingMixin = {
            handleChange: function(key) {
                var that = this
                var newState = {}
                return function(event) {  
                    newState[key] = event.target.value
                    that.setState(newState)
                }
            }
        }
        var BindingExample = React.createClass({
            mixins: [React.addons.LinkedStateMixin],
            getInitialState: function() {
                return {
                    text: ”,
                    comment: ”,
                }
            },
            render: function() {
                return <div>
                    <input type="text" placeholder="请输入内容" valueLink={this.linkState(‘text’)} />
                    <textarea valueLink={this.linkState(‘comment’)}></textarea>
                    <h3>{this.state.text}</h3>
                    <h3>{this.state.comment}</h3>
                </div>
            }
        })
        React.render(<BindingExample></BindingExample>, document.body);
    </script>
</body>
</html>

功能图(没有CSS样式,有点不佳看,见谅):

亚洲必赢官网 29

更多读书demo已上传至:

参考资料:

《React引领未来的用户界面开发框架》

极客大学视频课程

打赏匡助自己写出越来越多好小说,谢谢!

打赏作者

缓解方式

因为有前任的摸索,现在大家有Object-Oriented CSS,
BEM,
SMACSS等等,这几个都是可怜棒并且尤其实用的措施。他们通过增添前缀的艺术,解决了命名争执的题目。

经过增添前缀的法子化解命名争辩是个体力活(manual
mangling)。大家手动的去编写长长的选用器。你也得以利用预编译的css语言,但是它们并从未从根本上解决难题(依然体力活)。下边是大家用BEM规范书写的一个单身组件(对于现有的除BEM之外的方法,思想上着力也是这么):

CSS

/* 普通 CSS */ .article { font-size: 16px; } .article__title {
font-size: 24px; } /* 使用css预处理语言 */ .article { font-size: 16px;
&__title { font-size: 24px; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 普通 CSS */
.article {
  font-size: 16px;
}
 
.article__title {
  font-size: 24px;
}
 
/* 使用css预处理语言 */
.article {
  font-size: 16px;
 
  &__title {
    font-size: 24px;
  }
}

打赏辅助我写出更多好小说,谢谢!

任选一种支付办法

亚洲必赢官网 30
亚洲必赢官网 31

1 赞 3 收藏
评论

CSS模块(CSS Modules)

二零一五年出现了其余二种格局的落到实处。分别是CSS-in-JS
和 CSS
Modules。大家将保养钻探后者。

CSS模块允许你将具备css class自动打碎,那是CSS模块(CSS
Modules)的默许设置。然后生成一个JSON文件(sources
map)和原先的class关联:

CSS

/* post.css */ .article { font-size: 16px; } .title { font-weight:
24px; }

1
2
3
4
5
6
7
8
/* post.css */
.article {
  font-size: 16px;
}
 
.title {
  font-weight: 24px;
}

地点的post.css将会被转换成类似上面那样:

CSS

.xkpka { font-size: 16px; } .xkpkb { font-size: 24px; }

1
2
3
4
5
6
7
.xkpka {
  font-size: 16px;
}
 
.xkpkb {
  font-size: 24px;
}

被打碎替换的classes将被保存在一个JSON对象中:

JavaScript

`{ “article”: “xkpka”, “title”: “xkpkb” } `

1
`{  "article":  "xkpka",  "title":  "xkpkb"  }  `

在更换已毕后,你可以一贯引用那个JSON对象到品种中,那样就可以用事先写过的class名来直接运用它了。

JavaScript

import styles from ‘./post.json’; class Post extends React.Component {
render() { return ( <div className={ styles.article }> <div
className={ styles.title }>…</div> … </div> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
import styles from ‘./post.json’;
 
class Post extends React.Component {
  render() {
    return (
      <div className={ styles.article }>
        <div className={ styles.title }>…</div>
        …
      </div>
    );
  }
}

越来越多给力的功效, 可以看看
那篇越发好的稿子.

不只是保留了前面涉嫌的两种方法的助益,还自行解决了组件css分离的标题。那就是CSS模块(CSS
Modules),听起来分口腔科学啊!

到此地,大家有境遇了另一个标题: 大家后天的CSS
Modules相关工具,只能够在客户端(浏览器)使用,把它放到一个非Node.js的服务端环境中是那一个至极困难的。

至于小编:winty

亚洲必赢官网 32

前端工程师,前端爱好者。博客:

个人主页 ·
我的篇章 ·
1 ·
 

亚洲必赢官网 33

PostCSS-modules

为了在服务端和客户端都能接纳CSS
Modules,我写了个PostCSS-modules,它是一个PostCSS插件,让您可以在服务端使用模块化的CSS,并且服务端语言可以是Ruby,
PHP, Python 或者其余语言。

PostCSS是一个CSS预处理器,它是用JS落成的。它援救静态检查CSS,接济变量和混入(mixins),能让你利用现在还未被浏览器帮衬的未来CSS语法,内联图像等等。例如使用最为广泛的Autoprefixer,它只是PostCSS的一个插件。

一经您选拔Autoprefixer,
其实你早已在用PostCSS了。所以,添加PostCSS-modules到您的品种看重列表,并不是一件难事。我先给您打个样(实例),用Gulp
and
EJS,其实您可以用其余语言做类似的政工。

JavaScript

// Gulpfile.js var gulp = require(‘gulp’); var postcss =
require(‘gulp-postcss’); var cssModules = require(‘postcss-modules’);
var ejs = require(‘gulp-ejs’); var path = require(‘path’); var fs =
require(‘fs’); function getJSONFromCssModules(cssFileName, json) { var
cssName = path.basename(cssFileName, ‘.css’); var jsonFileName =
path.resolve(‘./build’, cssName + ‘.json’);
fs.writeFileSync(jsonFileName, JSON.stringify(json)); } function
getClass(module, className) { var moduleFileName =
path.resolve(‘./build’, module + ‘.json’); var classNames =
fs.readFileSync(moduleFileName).toString(); return
JSON.parse(classNames)[className]; } gulp.task(‘css’, function() {
return gulp.src(‘./css/post.css’) .pipe(postcss([ cssModules({ getJSON:
getJSONFromCssModules }), ])) .pipe(gulp.dest(‘./build’)); });
gulp.task(‘html’, [‘css’], function() { return
gulp.src(‘./html/index.ejs’) .pipe(ejs({ className: getClass }, { ext:
‘.html’ })) .pipe(gulp.dest(‘./build’)); }); gulp.task(‘default’,
[‘html’]);

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
// Gulpfile.js
var gulp         = require(‘gulp’);
var postcss      = require(‘gulp-postcss’);
var cssModules   = require(‘postcss-modules’);
var ejs          = require(‘gulp-ejs’);
var path         = require(‘path’);
var fs           = require(‘fs’);
 
function getJSONFromCssModules(cssFileName, json) {
  var cssName       = path.basename(cssFileName, ‘.css’);
  var jsonFileName  = path.resolve(‘./build’, cssName + ‘.json’);
  fs.writeFileSync(jsonFileName, JSON.stringify(json));
}
 
function getClass(module, className) {
  var moduleFileName  = path.resolve(‘./build’, module + ‘.json’);
  var classNames      = fs.readFileSync(moduleFileName).toString();
  return JSON.parse(classNames)[className];
}
 
gulp.task(‘css’, function() {
  return gulp.src(‘./css/post.css’)
    .pipe(postcss([
      cssModules({ getJSON: getJSONFromCssModules }),
    ]))
    .pipe(gulp.dest(‘./build’));
});
 
gulp.task(‘html’, [‘css’], function() {
  return gulp.src(‘./html/index.ejs’)
    .pipe(ejs({ className: getClass }, { ext: ‘.html’ }))
    .pipe(gulp.dest(‘./build’));
});
 
gulp.task(‘default’, [‘html’]);

大家只要求执行gulp任务,就能博取更换后的CSS文件和JSON文件,然后就足以在EJS模版里面用了:

XHTML

<article class=”<%= className(‘post’, ‘article’) %>”> <h1
class=”<%= className(‘post’, ‘title’) %>”>Title</h1> …
</article>

1
2
3
4
<article class="<%= className(‘post’, ‘article’) %>">
  <h1 class="<%= className(‘post’, ‘title’) %>">Title</h1>
  …
</article>

若果您想看看实际的代码,我在GitHub给你准备了个example。更加多的事例能够看PostCSS-modules和CSS
Modules


自在编写可保险的CSS,没有臃肿的mixins。长长的前缀将变成历史,欢迎来到未来的CSS世界。

1 赞 收藏
评论

亚洲必赢官网 34

网站地图xml地图