在前面我们通过四篇文章入门了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. Python学习笔记(3)

      1.元组 元组的定义符号是() ,元素定义与列表完全一致.不同的是元组的内容是不可变的. 2.字典 字典里面的内容是无序的. 字典的元素组成形式是 key:value key的定义规则:key是不 ...

  2. SSH框架整合(XML)

    Struts2+Spring+Hibernate导包 Struts2导入jar包 struts2/apps/struts2-blank.war/WEB-INF/lib/*.jar 导入与spring整 ...

  3. python strip()函数 介绍

    python strip()函数 介绍,需要的朋友可以参考一下   函数原型 声明:s为字符串,rm为要删除的字符序列 s.strip(rm)        删除s字符串中开头.结尾处,位于 rm删除 ...

  4. Service and controller in angularJs

    Separation of concern is at the heart while designing an AngularJS application. Your controller must ...

  5. Maven的配置和使用(三)

    下面记录下如何使用Maven进行jar包的管理和更新. 在Maven中我们是通过对pom.xml文件的配置来对项目的包进行管理的,找到该文件并打开: <project xmlns="h ...

  6. $event 获取对象

    用Angular给元素添加事件时获取可以用 $event 传递当前触发的事件的元素对象 页面上可以这样写 <img ng-src="" alt="" ng ...

  7. continue语句在for语句和while语句中的区别

    while语句的形式: while( expression ) statement for语句的形式: for( expression1; expression2;expression3 )   // ...

  8. 工厂模式(Factory)

    一.分类 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式主要分为三个,简单工厂模式(Simple Factory)/ 工厂方法模式(Fac ...

  9. UVA - 11604 General Sultan 题解

    题目大意: 有若干模式串,将某些模式串拼接起来(一个可以使用多次)形成一个长模式串,判断能否有两种或更多种不同的拼法拼成相同的模式串. 思路: 神奇的构图,暴力的求解. 可以发现,若有不同的拼法,则一 ...

  10. echo.js 延迟加载图片控件

    echo.js的github地址:https://github.com/toddmotto/echo   echo是一个独立的JavaScript.轻量级的.延迟图片加载插件,echo压缩后体积不到1 ...