【问题标题】:Radio Buttons with Styled Components for React带有样式组件的 React 单选按钮
【发布时间】:2019-10-18 18:53:59
【问题描述】:

我正在尝试使用样式化组件在 React 中设置一个单选按钮,使用 this pen 作为示例,但是同级选择器让我感到困惑。怎么转这个

.radio-input:checked ~ .radio-fill {
  width: calc(100% - 4px);
  height: calc(100% - 4px);
  transition: width 0.2s ease-out, height 0.2s ease-out;
}
.radio-input:checked ~ .radio-fill::before {
  opacity: 1;
  transition: opacity 1s ease;
}

在样式化的组件中插入 css?

谁能指出我的错误或做一个快速的笔演示?谢谢!这是我的完整代码:

import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { colors } from '../../../theme/vars';

export class RadioGroup extends React.Component {
  getChildContext() {
    const { name, selectedValue, onChange } = this.props;
    return {
      radioGroup: {
        name, selectedValue, onChange,
      },
    };
  }

  render() {
    const { Component, name, selectedValue, onChange, children, ...rest } = this.props;
    return <Component role="radiogroup" {...rest}>{children}</Component>;
  }
}

RadioGroup.childContextTypes = {
  radioGroup: PropTypes.object,
};

RadioGroup.propTypes = {
  name: PropTypes.string,
  selectedValue: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.bool,
  ]),
  children: PropTypes.node.isRequired,
  Component: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.func,
    PropTypes.object,
  ]),
};

RadioGroup.defaultProps = {
  name: '',
  selectedValue: '',
  Component: 'div',
};




// eslint-disable-next-line react/no-multi-comp
export class Radio extends React.Component {
  render() {
    const { name, selectedValue } = this.context.radioGroup;
    const { onChange, value, labelText } = this.props;
    let checked = false;

    if (selectedValue !== undefined) {
      checked = (value === selectedValue);
    }

    console.log('value: ', value);
    console.log('checked: ', checked);
    console.log('selectedValue: ', selectedValue);

    return (
      <Root>
        <Input
          type="radio"
          name={name}
          value={value}
          checked={checked}
          aria-checked={checked}
          onChange={onChange}
        />
        <Fill />
        {/* <div style={{ marginLeft: '25px' }}>{labelText}</div> */}
      </Root>
    );
  }
}

Radio.contextTypes = {
  radioGroup: PropTypes.object,
};

Radio.propTypes = {
  onChange: PropTypes.func,
  value: PropTypes.string,
  labelText: PropTypes.string,
};

Radio.defaultProps = {
  onChange: () => {},
  value: '',
  labelText: '',
};


const Root = styled.div`
  width: ${props => props.size ? props.size : 20}px;
  height: ${props => props.size ? props.size : 20}px;
  position: relative;

  &::before {
    content: '';
    border-radius: 100%;
    border: 1px solid ${props => props.borderColor ? props.borderColor : '#DDD'};
    background: ${props => props.backgroundColor ? props.backgroundColor : '#FAFAFA'};
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    box-sizing: border-box;
    pointer-events: none;
    z-index: 0;
  }
`;

const Fill = styled.div`
  background: ${props => props.fillColor ? props.fillColor : '#A475E4'};
  width: 0;
  height: 0;
  border-radius: 100%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transition: width 0.2s ease-in, height 0.2s ease-in;
  pointer-events: none;
  z-index: 1;

  &::before {
    content: '';
    opacity: 0;
    width: calc(20px - 4px);
    position: absolute;
    height: calc(20px - 4px);
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border: 1px solid ${props => props.borderActive ? props.borderActive : '#A475E4'};
    border-radius: 100%;
  }
`;

const Input = styled.input`
  opacity: 0;
  z-index: 2;
  position: absolute;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;

  &:focus {
    outline: none;
  }

  &:checked {
    ${Fill} {
      width: calc(100% - 8px);
      height: calc(100% - 8px);
      transition: width 0.2s ease-out, height 0.2s ease-out;

      &::before {
        opacity: 1;
        transition: opacity 1s ease;
      }
    }

  }
`;

以及组件的用法:

<RadioGroup name="setYAxis" onChange={e => this.toggleSetYAxis(e)} selectedValue={this.state.setYAxis}>
  <Radio value="autoscale" labelText="Autoscale" />
  <Radio value="manual" labelText="Manual" />
</RadioGroup>

【问题讨论】:

标签: reactjs radio-button styled-components


【解决方案1】:

我创建了一个codesandbox 来修复css 问题和状态管理问题。 提供的代码更简单,不依赖过时的 React 上下文 API (doc here)

【讨论】:

  • 嗨 Gaël,我似乎无法选择您的 codepen 中的其他单选按钮,似乎仍然是状态管理问题。
  • 非常感谢盖尔!
【解决方案2】:

您在填充选择器之前缺少 ~:

  &:checked {
    & ~ ${Fill} {
      width: calc(100% - 8px);
      height: calc(100% - 8px);
      transition: width 0.2s ease-out, height 0.2s ease-out;

      &::before {
        opacity: 1;
        transition: opacity 1s ease;
      }
    }

在本例中,您实际上更新状态的方式似乎也有问题,但这与样式无关:在RadioGroup 上,您没有将onChange 属性传递给Radio。扩展运算符的方式使您的 const rest 仅包含您尚未在 const 中定义的属性。所以你需要从那里删除它的onChange声明,让它进入rest

export class RadioGroup extends React.Component {
  getChildContext() {
    const { name, selectedValue, onChange } = this.props;
    return {
      radioGroup: {
        name,
        selectedValue,
        onChange
      }
    };
  }

  render() {
    const {
      Component,
      name,
      selectedValue,
      // Remove onChange from here
      // onChange, 
      children,
      ...rest
    } = this.props;
    return (
      <Component role="radiogroup" {...rest}>
        {children}
      </Component>
    );
  }
}

工作示例:https://codesandbox.io/s/serene-cdn-1fw1i

【讨论】:

    猜你喜欢
    • 2012-11-28
    • 2016-07-11
    • 2021-12-16
    • 2021-06-19
    • 1970-01-01
    • 2018-12-17
    • 2018-08-03
    • 2020-08-02
    • 2017-12-30
    相关资源
    最近更新 更多