React 动画按钮组件

 标题,下划线 动画

 禁用

import React from 'react'
import {RadioButton, RadioButtonGroup} from 'material-ui/RadioButton'
import MenuItem from 'material-ui/MenuItem'
import get from 'lodash/get'
import styled from "styled-components";
const Checked = <svg t="1606281388606" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2858" width="30" height="30">
    <path
        d="M512 810.667c-164.693 0-298.667-134.016-298.667-298.667s133.973-298.667 298.667-298.667c164.651 0 298.667 134.016 298.667 298.667s-134.016 298.667-298.667 298.667zM512 253.184c-142.72 0-258.859 116.096-258.859 258.816s116.139 258.816 258.859 258.816c142.763 0 258.816-116.181 258.816-258.816 0-142.763-116.053-258.816-258.816-258.816z"
        p-id="2859" fill="#00bcd4" />
    <path
        d="M682.667 512c0 94.257-76.41 170.667-170.667 170.667s-170.667-76.41-170.667-170.667c0-94.257 76.41-170.667 170.667-170.667s170.667 76.41 170.667 170.667z"
        p-id="2860" fill="#00bcd4" />
</svg>

const UnChecked = <div style={{30,height:30,marginTop:1}}>
    <svg t="1606281728538" className="icon" viewBox="0 0 1024 1024" version="1.1"
         xmlns="http://www.w3.org/2000/svg" p-id="3340" width="29" height="29">
        <path
            d="M512 810.667c-164.693 0-298.667-134.016-298.667-298.667s133.973-298.667 298.667-298.667c164.651 0 298.667 134.016 298.667 298.667s-134.016 298.667-298.667 298.667zM512 253.184c-142.72 0-258.859 116.096-258.859 258.816s116.139 258.816 258.859 258.816c142.763 0 258.816-116.181 258.816-258.816 0-142.763-116.053-258.816-258.816-258.816z"
            p-id="3341"/>
    </svg>
</div>

const DisableChecked = <svg t="1606281388606" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2858" width="30" height="30">
    <path
        d="M512 810.667c-164.693 0-298.667-134.016-298.667-298.667s133.973-298.667 298.667-298.667c164.651 0 298.667 134.016 298.667 298.667s-134.016 298.667-298.667 298.667zM512 253.184c-142.72 0-258.859 116.096-258.859 258.816s116.139 258.816 258.859 258.816c142.763 0 258.816-116.181 258.816-258.816 0-142.763-116.053-258.816-258.816-258.816z"
        p-id="2859" fill="rgba(0, 0, 0, 0.3)" />
    <path
        d="M682.667 512c0 94.257-76.41 170.667-170.667 170.667s-170.667-76.41-170.667-170.667c0-94.257 76.41-170.667 170.667-170.667s170.667 76.41 170.667 170.667z"
        p-id="2860" fill="rgba(0, 0, 0, 0.3)" />
</svg>
const DisableUnChecked = <div style={{30,height:30,marginTop:1}}>
    <svg t="1606281728538" className="icon" viewBox="0 0 1024 1024" version="1.1"
         xmlns="http://www.w3.org/2000/svg" p-id="3340" width="29" height="29">
        <path
            d="M512 810.667c-164.693 0-298.667-134.016-298.667-298.667s133.973-298.667 298.667-298.667c164.651 0 298.667 134.016 298.667 298.667s-134.016 298.667-298.667 298.667zM512 253.184c-142.72 0-258.859 116.096-258.859 258.816s116.139 258.816 258.859 258.816c142.763 0 258.816-116.181 258.816-258.816 0-142.763-116.053-258.816-258.816-258.816z"
            p-id="3341" fill='rgba(0, 0, 0, 0.3)' />
    </svg>
</div>
let font = 16;

class RadioButtons extends React.Component {
    constructor(props) {
        const {defaultValue} = props;
        super(props);
        this.state = {
            checked: defaultValue,
            tp:40,
            lf:5,
            transform:false
        }
    }


    handleChange = (e) => {
        const {onChange} = this.props;
        this.setState({
            checked:e.value,
            transform:true,
        })
        setTimeout(()=>{
            this.setState({
                transform:false
            })
        },400)
        if (typeof onChange === 'function') {
            onChange(e.value);
        }
    }


    componentDidMount() {
        // 标题动画
        const {defaultValue,onChange} = this.props;
        setTimeout(()=>{
            this.setState({
                fs:14,
                tp:15,
                lf:0
            })
        },10)
        if(defaultValue){
            onChange(defaultValue)
        }
    }


    diff(obj1, obj2) {
        let o1 = obj1 instanceof Object;
        let o2 = obj2 instanceof Object;
        if (!o1 || !o2) {/*  判断不是对象  */
            return obj1 === obj2;
        }

        if (Object.keys(obj1).length !== Object.keys(obj2).length) {
            return false;
            //Object.keys() 返回一个由对象的自身可枚举属性(key值)组成的数组,例如:数组返回下表:let arr = ["a", "b", "c"];console.log(Object.keys(arr))->0,1,2;
        }

        for (let attr in obj1) {
            let t1 = obj1[attr] instanceof Object;
            let t2 = obj2[attr] instanceof Object;
            if (t1 && t2) {
                return this.diff(obj1[attr], obj2[attr]);
            } else if (obj1[attr] !== obj2[attr]) {
                return false;
            }
        }
        // 如果相等,返回true
        return true;
    }

    componentWillReceiveProps(nextProps, nextContext) {
        if(!this.diff(nextProps.defaultValue,this.props.defaultValue)){
            this.setState({
                checked: nextProps.defaultValue
            },()=>{
                this.props.onChange(nextProps.defaultValue &&nextProps.defaultValue);
            })
        }
        if(!this.diff(nextProps.options,this.props.options)){
            this.setState({
                checked:nextProps.options && nextProps.options[0].value
            },()=>{
                this.props.onChange(nextProps.options &&nextProps.options[0].value);
            })
        }
    }

    render() {
        const {
            value,
            disabled,
            options,
            optionText,
            optionValue,
            floatingLabelText,
            errorText
        } = this.props;
        const {checked,transform} = this.state;
        return (
            <RadioButtons.Root>
                <span className={'radioTitle'} style={{
                    top:this.state.tp,
                    left:this.state.lf,
                    color: disabled ? 'rgba(0, 0, 0, 0.3)'  : transform ? 'rgba(14,119,209)':'rgba(0, 0, 0, 0.3)'
                }} >{floatingLabelText}</span>
                <div className={'radioBox'} style={{
                    borderBottom: disabled ? '2px dotted rgba(0 ,0 ,0 ,.3)' : errorText ? '2px solid #f44336' : '1px solid rgba(178,178,178,.4)'
                }}
                >
                    {options.map(item=>(
                        <div
                            key={item.value}
                            className={'radioItem'}
                            onClick={()=>{
                                if (disabled){
                                    return
                                }
                                this.handleChange(item)
                            }}
                        >
                            {checked === item.value ? ( disabled ? DisableChecked: Checked) : ( disabled ? DisableUnChecked: UnChecked)} <span style={{color:disabled?'rgba(0, 0, 0, 0.3)':'#333'}}>{item.text}</span>
                        </div>
                    ))}
                </div>
                <hr className={'transformLine'} style={{
                    transform: transform ? 'scaleX(1)' :'scaleX(0)'
                }}/>
                <div className={'errorText'}>{errorText}</div>
            </RadioButtons.Root>

        )
    }
}

setTimeout(()=>{
    font = 12
},1000)
RadioButtons.Root = styled.div`
      position:relative;
      padding-top: 10px;
      margin-top: 20px;
      margin-bottom: 8px;
     .radioTitle {
        transition: all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
        z-index: 1;
        transform: scale(0.75) translate(0px, -28px);
        transform-origin: left top;
        pointer-events: none;
        user-select: none;
        position: absolute;
     }
     .radioBox {
        display:flex;
        align-items: center;
        justify-content: space-around;
     }
     .radioItem {
        display:flex;
        align-items: center;
     }
     .errorText {
        position: relative;
        bottom: -5px;
        font-size: 12px;
        line-height: 12px;
        color: rgb(244, 67, 54);
        transition: all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
     }
     .transformLine {
        border-top: none rgb(14, 119, 209);
        border-left: none rgb(14, 119, 209);
        border-right: none rgb(14, 119, 209);
        border-bottom: 2px solid rgb(14, 119, 209);
        bottom: 8px;
        box-sizing: content-box;
        margin: 0px;
        bottom:0;
        position: absolute;
         100%;
        transition: all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
     } 
`

export default RadioButtons;
原文地址:https://www.cnblogs.com/it-Ren/p/14043728.html