reactjs - 带有 React 样式组件的单选按钮

标签 reactjs radio-button styled-components

我正在尝试使用 this pen 使用样式组件在 React 中实现单选按钮集。然而,作为一个例子,同级选择器让我绊倒了。怎么转这个

.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>

最佳答案

我创建了一个codesandbox修复CSS问题和状态管理问题。 提供的代码更简单,并且不依赖于过时的 React context API (doc here)

关于reactjs - 带有 React 样式组件的单选按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56423614/

相关文章:

javascript - react-router - 将 Prop 传递给处理程序组件

android - 如何自定义列表首选项单选按钮

javascript - 使用 TypeScript 打字的样式化系统 Prop

javascript - 在 ReactJS 中将文本名称渲染为组件

javascript - &lt;script&gt; 标签中的内容到 ReactJS 组件

java - 数据源: 'url' attribute is not specified and no embedded datasource could be configured

html - 单选按钮上的动态 CSS 动画

android - Android 上带边距的单选按钮左侧的文本

css - MUI - 如何在特定样式的组件中使用伪类

reactjs - 退出react-bootstrap modal时如何阻止事件冒泡?