React 組件開發入門

前言

熟悉 React 的思想後,咱們先來嘗試開發一個單純的小組件,能夠對比一下是否是比之前的開發模式更加溫馨了,這裏我主要以一個 Loadding 組件來舉栗子,實現了幾個基本的功能:react

  • 一種類型的 loadding(菊花轉)web

  • 可以設置 loadding 的三個屬性:width height color動畫

  • 可以控制 loadding 的顯示和隱藏this

其實對於一個簡單需求來講,這三個屬性已經很實用了。可是去網上看一些外國大神寫的組件,有一些不明白的地方,因此本身就慢慢搞,do it!spa

設計

我想這樣用 loadding 組件:設計

圖片描述

因此我定義這個組件的基本結構以下:code

var Loadding = React.createClass({
    // 控制組件屬性的類型
    propTypes: {},
    // 控制組件屬性的默認值
    getDefaultProps: function () {},
    // 組裝基本的內聯樣式
    getComponentStyle: function () {},
    // 渲染基本的組件,拆分 render 方法的粒度
    renderBaseComp: function () {},
    // 最終的渲染方法
    render: function () {}
});

這個組件中,我使用的 內聯樣式 來控制組件的內部基本樣式的穩定。其實有時候咱們會以爲內聯樣式很差,可是我我的以爲每一種設置 CSS 形式的方法,用在合適的場景中就是正確的。orm

每部分的具體實現以下,代碼中有一些講解(這裏我不會介紹具體 loadding 效果是怎麼出來的,看代碼應該就會明白,主要介紹一個 react 製做簡單組件的思路和寫法)對於擴展性來講,blog

你還能夠加入 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;
}
相關文章
相關標籤/搜索