React 组件开发入门

er74 9年前

 

前言

熟悉 React 的思想后,我们先来尝试开发一个单纯的小组件,可以对比一下是不是比以前的开发模式更加舒适了,这里我主要以一个 Loadding 组件来举栗子,实现了几个基本的功能:

  • 一种类型的 loadding(菊花转)
  • 能够设置 loadding 的三个属性:width height color
  • 能够控制 loadding 的显示和隐藏

其实对于一个简单需求来说,这三个属性已经很实用了。但是去网上看一些外国大神写的组件,有一些不明白的地方,所以自己就慢慢搞,do it!

设计

我想这样用 loadding 组件:

React 组件开发入门

所以我定义这个组件的基本结构如下:

var Loadding = React.createClass({    // 控制组件属性的类型    propTypes: {},    // 控制组件属性的默认值    getDefaultProps: function () {},    // 组装基本的内联样式    getComponentStyle: function () {},    // 渲染基本的组件,拆分 render 方法的粒度    renderBaseComp: function () {},    // 最终的渲染方法    render: function () {}  });

这个组件中,我使用的 内联样式 来控制组件的内部基本样式的稳定。其实有时候我们会觉得内联样式不好,但是我个人觉得每一种设置 CSS 形式的方法,用在合适的场景中就是正确的。

每部分的具体实现如下,代码中有一些讲解(这里我不会介绍具体 loadding 效果是怎么出来的,看代码应该就会明白,主要介绍一个 react 制作简单组件的思路和写法)对于扩展性来说,

你还可以加入 className 和 type 这些修饰性的属性,但是我更倾向于迭代式的组件开发,小组件就要具有良好的封闭性,使用接口简单,大组件才考虑更好的鲁棒性和可扩展性,这样开发一个组件 的性价比才高。需要注意对 getDefaultProps 的理解,只有当使用接口的人代码中根本没有写那个属性的时候,才会使用定义的默认值。

实现

var Loadding = React.createClass({    propTypes: {      width: React.PropTypes.oneOfType([        React.PropTypes.number,        React.PropTypes.string      ]),      height: React.PropTypes.oneOfType([        React.PropTypes.number,        React.PropTypes.string      ]),      color: React.PropTypes.string,      active: React.PropTypes.bool    },    getDefaultProps: function() {      return {        color: '#00be9c',        height: 30,        width: 30,        active: false      };    },    getComponentStyle: function() {      var width = this.props.width,        height = this.props.height,        color = this.props.color;      /* 中间圆心 */      var cWidth = 0.4 * width,        cHeight = 0.4 * height,        cMarginLeft = -0.5 * cWidth,        cMarginTop = -0.5 * cHeight;      /* 基本样式 */      return {        loaddingStyle: { // loadding 容器          width: width,          height: height        },        lineStyle: { // loadding 元件样式          background: color        },        centerStyle: { // loadding 圆心样式          width: cWidth,          height: cHeight,          marginLeft: cMarginLeft,          marginTop: cMarginTop        }      };    },    renderBaseComp: function(compStyle) {      /* 生成动画元件 */      var n = 4; // 元件个数,todo: 定制个数      var lines = []; // 元件元素集合      for (var i = 0; i < n; i++) {        lines.push(          <div className="line">            <span className="top" style={ compStyle.lineStyle }></span>            <span className="bottom" style={ compStyle.lineStyle }></span>          </div>        );      }      return lines;    },    render: function() {      /* 生成组件自己的样式 */      var compStyle = this.getComponentStyle();      /* 模拟渲染基本动画元件 */      var lines = this.renderBaseComp(compStyle);      // loadding 的class,控制交互      var loaddingClasses = cx({        loadding: true,        active: this.props.active      });      return (        <div className={ loaddingClasses } style={ compStyle.loaddingStyle }>          {lines}          <div className="loadding-center" style={ compStyle.centerStyle }></div>        </div>      );    }  });

最后,下面是基本的 SASS(不考虑不支持的情况,不支持都不用开发,直接用图,性价比更高)
@include keyframes(load) {    0% {      opacity: 0;    }    25% {      opacity: .25;    }    50% {      opacity: .5;    }    75% {      opacity: .75;    }    100% {      opacity: 1;    }  }  .loadding {    display: none;    position: absolute;    &.active {      display: block;    }    .loadding-center {      position: absolute;      left: 0;      top: 50%;      background: #fff;      border-radius: 50%;    }    .line {      position: absolute;      top: 0;      left: 0;      height: 100%;      .top {        content: '';        display: block;        width: 1px;        font-size: 0;        height: 50%;      }      .bottom {        @extend .top;      }      @for $i from 1 through 4 {        &:nth-child(#{$i}) {          transform:rotate(45deg * ($i - 1));          .top {            @include animation(load, 0.8s, linear, 0s, infinite);          }          .bottom {            @include animation(load, 0.8s, linear, 0.4s + $i/10, infinite);          }        }      }    }  }

里面用到的一个 animation 混淆方法:
@mixin keyframes($name) {    @-webkit-keyframes #{$name} {      @content;    }    @-moz-keyframes #{$name} {      @content;    }    @-ms-keyframes #{$name} {      @content;    }    @keyframes #{$name} {      @content;    }  }  @mixin animation ($name, $duration, $func, $delay, $count, $direction: normal) {    -webkit-animation: $name $duration $func $delay $count $direction;    -moz-animation: $name $duration $func $delay $count $direction;    -o-animation: $name $duration $func $delay $count $direction;    animation: $name $duration $func $delay $count $direction;  }