在前面我们通过四篇文章入门了React的大部分主要API,现在则开始进入实践环节。

实践系列的开篇打算拿我司的FrozenUI来试验,将其部分UI组件进行React化,作为第一篇实践文章,将以较简单的Loading组件来入手,官网demo的效果如下图:

为了更好地开发,后续将以webpack工具来辅助,对其不了解的童鞋可以先查阅我的《webpack 入门指南》一文。

鉴于我们将复用 FrozenUI 的样式,所以在DOM结构、class命名上都应当尽量和原版的保持一致,在这个基础上来实现具有同样功能的React组件。

于是我们先下载好 frozen.css(方便示例所以直接用全局的样式)和图片资源,并定义一个简单的 webpack.config.js:

    module.exports = {
entry: {
loading : './src/js/page/loading.js'
},
output: {
path: 'dist/js/page',
filename: '[name].js'
},
module: {
loaders: [
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.js$/, loader: 'jsx-loader?harmony' },
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
]
},
resolve: {
extensions: ['', '.js', '.json', '.scss']
}
};

需要下载的模块大致有这些(尽管有几个我们暂时还用不上,先装上无所谓)

  "dependencies": {
"css-loader": "^0.15.2",
"expose-loader": "^0.7.0",
"file-loader": "^0.8.4",
"jsx-loader": "^0.13.2",
"node-sass": "^3.2.0",
"react": "^0.13.3",
"sass-loader": "^1.0.2",
"style-loader": "^0.12.3",
"url-loader": "^0.5.6"
}

我们的文件目录结构也很简单:

其中 src 为源文件文件夹,dist 用于存放 webpack 最终处理后的输出文件。

src/js 中又分了 component 和 page 两个文件夹,用于存放组件脚本和html页面上要引用的入口脚本。

./loading.html

这是最终执行页面,作为Demo可以做的简单点:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Demo</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
</head>
<body>
<div class="wrap"></div>
<script src="dist/js/page/loading.js"></script>
</body>
</html>

其中类名为wrap的div是方便我们挂载Loading组件的容器,整个页面也只有一个script脚本入口(样式也将最终打包在里面)

./src/js/page/loading.js

我们先写好该页面入口脚本,确定好Loading组件的使用锥形:

require('../../css/frozen.css'); //把样式引进来
var React = require('react'),
Loading = require('../component/Loading'); //这是组件模块,下一步要写的东西 var wrap = document.querySelector('.wrap'),
hideCallback = function(){ //卸载组件后的回调
alert('done!!');
}; React.render(
<Loading content='哈喽' onHide={hideCallback}/>, wrap
); setTimeout(function(){ //3秒后卸载组件,模拟触发回调
React.unmountComponentAtNode(wrap)
}, 3000);

我们希望能够自定义Loading组件上所显示的文字,以及它被隐藏掉时触发的回调,故我们使用两个props——“content”和“onHide”来绑定(事实上还有一个判断是否只在局部显示“加载中”的props属性“isPart”,但新版的FrozenUI取消了该功能)

./src/js/component/Loading.js

这块是Loading组件模块,是最重要的模块,用于实现Loading组件的全部功能。

注意常规我们要求React组件模块的首字母必须大写。

初步写出一个简单的组件结构:

    var React = require('react'),
PropTypes = React.PropTypes; var Loading = React.createClass({ propTypes: {
onHide: PropTypes.func, //组件卸载后的回调
content: PropTypes.string // 展示内容
}, componentWillUnmount: function(){ //卸载时的回调
if(typeof this.props.onHide === 'function'){
setTimeout(this.props.onHide, 10);
}
}, render: function () {
var content = this.props.content || '正在加载中...',
component = (<div>{content}</div>); return component
}
}); module.exports = Loading;

对于两个绑定的props,我们分别在 componentWillUnmount 和 render 中做了对应处理,从而决定了组件卸载时是否触发回调,以及加载时显示什么内容(若未传props.content,则默认为“正在加载中...”),接着我们要处理的是最终渲染的DOM结构(总不能只有一个div对吧),这块我们得分析现有的 Frozen-Loading组件的DOM结构,尽量与其一致(包括类名的定义):

那么我们只需要在 render 里直接套用这块DOM结构,把<p>标签里的内容换成 {content} 即可。

不过这样好像太简单了,不怎么好玩呢~

在上个版本的Frozen-Loading组件里,是有区分全局展示/局部展示加载界面的,局部加载是酱紫的:

我还记得局部展示情况下的DOM结构和样式(实际上它们只是类名不同),于是打算增加个 props.isPart 来判断用户是否要局部展示,并且这样改写组件代码:

    var React = require('react'),
loadingCN = require('../component/styleMaps').loadingCN, //引入加载组件类名对象
PropTypes = React.PropTypes; var Loading = React.createClass({ propTypes: {
isPart: PropTypes.bool, //是否局部加载
onHide: PropTypes.func, //组件卸载后的回调
content: PropTypes.string // 展示内容
}, componentWillUnmount: function(){
if(typeof this.props.onHide === 'function'){
setTimeout(this.props.onHide, 10);
}
}, render: function () {
var content = this.props.content || '正在加载中...',
flag = this.props.isPart ? 'partial' : 'global',
component = (<div className={loadingCN.block[flag]}>
<div className={loadingCN.wrap[flag]}>
<i className={loadingCN.i[flag]}></i>
<p>{content}</p>
</div>
</div>); return component
}
}); module.exports = Loading;

留意一个比较有趣的地方,我们通关一个变量flag来判断用户是希望全局显示还是局部显示加载界面,然后通过这个标签来获取到对应的类名:

                flag = this.props.isPart ? 'partial' : 'global',
component = (<div className={loadingCN.block[flag]}>
<div className={loadingCN.wrap[flag]}>
<i className={loadingCN.i[flag]}></i>
<p>{content}</p>
</div>
</div>);

而此处的 loadingCN 是我们在开头引入的一个共用模块:

loadingCN = require('../component/styleMaps').loadingCN

该模块的定义也非常简单:

./src/js/component/styleMaps.js

    module.exports = {
globalCN: {},
loadingCN: {
block: {
partial: 'demo-block',
global: 'ui-loading-block show'
},
wrap: {
partial: 'ui-loading-wrap',
global: 'ui-loading-cnt'
},
i: {
partial: 'ui-loading',
global: 'ui-loading-bright'
}
}
};

其返回了一个存放各组件类名对象,因此我们可以通过 require('../component/styleMaps').loadingCN.block['global'] 的形式来获取到Loading组件全局加载时最外层div的类名。

于是乎我们为啥要这么折腾多搞个样式模块呢?直接写在 Loading.js 里不行么?

答案是可以,但是多出一个样式模块可以方便我们后期统一在一个文件里维护所有组件的类名,实际上是为后期维护提供了一定便捷度。

另外该样式管理模块我们也暂时腾出了一个叫 globalCN 的对象属性,可以作为存放多个组件间共用的类名。

我们执行 webpack 打包后访问根目录的 loading.html(模拟移动端),效果正合我们预期呢:

我们给 page/loading.js 要渲染的组件加上 isPart={true} ,让其走局部加载形式:

React.render(
<Loading content='哈喽' onHide={hideCallback} isPart={true}/>, wrap
);

运行结果也是666:

本次的实践就这么愉快的结束吧~ 本节的代码可以在我的Github下载到。

下次分享下稍复杂点的 Tab 面板的React化的实现。共勉~!

如果觉得有帮助,就帮忙点下推荐吧,不然感觉每次写这种系列的文章好吃亏都没人支持。。。都不太想继续写了\("▔□▔)/

ReactJS实践(一)—— FrozenUI React化之Loading组件的更多相关文章

  1. React Native封装Toast与加载Loading组件

    React Native开发封装Toast与加载Loading组件 在App开发中,我们避免不了使用的两个组件,一个Toast,一个网络加载Loading,在RN开发中,也是一样,React Nati ...

  2. React 之 高阶组件的理解

    1.基本概念 高阶组件是参数为组件,返回值为新组件的函数. 2.举例说明 ① 装饰工厂模式 组件是 react 中的基本单元,组件中通常有一些逻辑(非渲染)需要复用处理.这里我们可以用高阶组件对组件内 ...

  3. 我们一起来详细的了解react的语法以及组件的使用方法

    jsx的介绍 React 使用 JSX 来替代常规的 JavaScript. JSX 是一个看起来很像 XML 的 JavaScript 语法扩展. jsx的优点 JSX 执行更快,因为它在编译为 J ...

  4. 从 Vue 的视角学 React(四)—— 组件传参

    组件化开发的时候,参数传递是非常关键的环节 哪些参数放在组件内部管理,哪些参数由父组件传入,哪些状态需要反馈给父组件,都需要在设计组件的时候想清楚 但实现这些交互的基础,是明白组件之间参数传递的方式, ...

  5. React Hooks中父组件中调用子组件方法

    React Hooks中父组件中调用子组件方法 使用到的hooks-- useImperativeHandle,useRef /* child子组件 */ // https://reactjs.org ...

  6. react native之组织组件

    这些组件包括<TabView>,<NavigatorView>和<ListView>,他们实现了手机端最常用的交互和导航.你会发现这些组件在实际的项目中会非常有用. ...

  7. React和Vue的组件更新比较

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 24.0px "Helvetica Neue"; color: #404040 } p. ...

  8. reactjs-swiper react轮播图组件基于swiper

    react轮播图组件基于swiper demo地址:http://reactjs-ui.github.io/reactjs-swiper/simple.html 1. 下载安装 npm install ...

  9. 小程序实践(六):view内部组件排版

    涉及知识点: 1.垂直排列,水平排列 2.居中对齐 示例: 1.默认排版 , 一个父组件里面两个子view 显示效果: 2.先给父view设置一个高度和颜色值,用于看效果 3.实现水平排列和垂直排列的 ...

随机推荐

  1. IntelliJ Idea 常用快捷键 列表

    1. -----------自动代码-------- 常用的有fori/sout/psvm+Tab即可生成循环.System.out.main方法等boilerplate样板代码 例如要输入for(U ...

  2. Power服务器中KVM克隆新虚拟机

    查看当前所有虚拟机:virsh list --all 克隆新虚拟机:virt-clone  -o guest01 -n guest02 -f /var/lib/libvirt/images/guest ...

  3. Java 之 集合框架(JCF)

    1.集合框架 a.框架:为了实现某一目的或功能,而预先提供的一系列封装好的.具有继承或实现关系的类与集合 b.集合:①定义:Java中对一些数据结构和算法进行封装,即封装(集合也是一种对象) ②特点: ...

  4. z-stack组网过程

    z-stack组网分:协调器建立网络.路由器和终端加入网络 暂时只记录第一次上电建立网络的过程,至于开启NV_RESTORE后,恢复原有的网络则暂时不分析. 一.协调器建立网络: 1.ZDO层的ZDA ...

  5. nodejs复习04

    TCP/UDP网络应用 创建TCP服务器客户端 socket套接字对象实例,是对TCP协议的一个基本封装接口 clientt套接字对象实例 //server.js var net = require( ...

  6. 截取QueryString 通过截取?和& 小写

    $(function () { var url = location.href.replace("#", ""); var paraString = url.s ...

  7. 域名扫描工具Fierce

    域名扫描工具Fierce   该工具是一个域名扫描综合性工具.它可以快速获取指定域名的DNS服务器,并检查是否存在区域传输(Zone Transfer)漏洞.如果不存在该漏洞,会自动执行暴力破解,以获 ...

  8. 转:Delphi2010新发现-类的构造和析构函数功能

    Delphi2010发布了. 虽然凭着对Delphi的热爱第一时间就安装了,但是现在可能是年纪大了,对新事物缺乏兴趣了.一直都没有仔细研究. 今天有点时间试了一下新功能. 本来C#和Delphi.NE ...

  9. css定位学习经验记录

    之前了解到css的定位position属性,常用的三种: position:absolute 1.当父元素定位为relative时,以父元素为起始坐标定位. 2.当父元素没有定位时,以body为起始坐 ...

  10. React生命周期

    在react生命周期中,分2段执行,一个挂载的生命周期,一个是组件发生了数据变动,或者事件触发而引发的更新生命周期. 注:react生命周期很重要,对于很多组件场景的应用发挥重要作用,而且不熟悉生命周 ...