ReactJS实践(一)—— FrozenUI React化之Loading组件

在前面我们通过四篇文章入门了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化的实现。共勉~!

时间: 2024-10-21 16:59:42

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

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

jsx的介绍 React 使用 JSX 来替代常规的 JavaScript. JSX 是一个看起来很像 XML 的 JavaScript 语法扩展. jsx的优点 JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化. 它是类型安全的,在编译过程中就能发现错误. 使用 JSX 编写模板更加简单快速. JSX的使用方法 独立文件 内联样式 注释 JSX的语法 JavaScript 表达式的使用 三元运算的使用 数组化标签 关于组件 函数定义了一个组件: 函数定义名字使用驼峰方法

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

组件化开发的时候,参数传递是非常关键的环节 哪些参数放在组件内部管理,哪些参数由父组件传入,哪些状态需要反馈给父组件,都需要在设计组件的时候想清楚 但实现这些交互的基础,是明白组件之间参数传递的方式,和各自的优缺点 一.父组件传参到子组件 和 Vue 一样,React 中从父组件到子组件的传参也是通过 props 不过在 Vue 项目中,需要在先组件里定义将要接收的 props,而 React 可以直接获取 而且 props 不光可以接收 Number.String 等基本类型,还可以接收 Fu

初学React:定义一个组件

接着聊React,今天说说如何创建一个组件类. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React工程模板</title> <!-- react.js 是React的核心库 --> <script src="./build/react.js charset="

React Native常用第三方组件汇总--史上最全 之一

把我认为最好的知识,拿来与他人分享,是这一生快事之一! React Native 项目常用第三方组件汇总: react-native-animatable 动画 react-native-carousel 轮播 react-native-countdown 倒计时 react-native-device-info 设备信息 react-native-fileupload 文件上传 react-native-icons 图标 react-native-image-picker 图片选择器 reac

HT全矢量化的图形组件设计

HT一直被客户称道的就是其全矢量化的设计特色,矢量相比传统图片好处太多了: 矢量可无级缩放,界面不失真不模糊 描述矢量的文本内容远比图片小得多 目前各种window.devicePixelRatio不一致的设备,矢量可能是唯一彻底的解决方案 业务数据绑定 提起矢量一般都会想到SVG,但这是个坑人的玩意儿,这么多年就没见一个完善的实现者,浏览器实现千差万别,高级属性根本不能玩,Adobe SVG Viewer好多年前就停止更新,Flex支持SVG导入也仅供基本属性玩玩,当然SVG也不是一无是处hi

Flex 编写 loading 组件

Flex 界面初始化有时那个标准的进度条无法显示,界面长时间会处理空白的状态!我们来自定义一个进度条, 这个进度条加载在 Application 应用程序界面的 <s:Application 标签的 preinitialize 属性上: preinitialize="preInit(event, '')" 它就可以比 Flex 自执行的正常显示. 1.组件ZtipWindow.mxml <?xml version="1.0" encoding="

React和Vue的组件更新比较

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

React Native 学习-组件说明和生命周期

组件的详细说明(Component Specifications) 当通过调用 React.createClass() 来创建组件的时候,你应该提供一个包含 render 方法的对象,并且也可以包含其它的在这里描述的生命周期方法. 如图,可以把组件生命周期大致分为三个阶段: 第一阶段:是组件第一次绘制阶段,如图中的上面虚线框内,在这里完成了组件的加载和初始化: 第二阶段:是组件在运行和交互阶段,如图中左下角虚线框,这个阶段组件可以处理用户交互,或者接收事件更新界面: 第三阶段:是组件卸载消亡的阶

2017.11.30 React基础语法之一组件

1.推荐一个React学习中文网站:http://www.css88.com/react/ 2.使用jsx来将代码封装成React组件,然后像插入普通 HTML 标签一样,在其他地方插入这个组件.使用React.createClass用于生成一个组件 var MyComponent=React.createClass({ render: function() { return <h1>Hello world!</h1>; } }); ReactDOM.render( <MyC