简体   繁体   English

如何设置类似于 Material-UI 的轮廓文本字段的 static 轮廓 div?

[英]How can I set an static outlined div similar to Material-UI's outlined textfield?

I want wrap some TextFields in a outlined container and I found this answer .我想将一些 TextFields 包装在一个概述的容器中,我找到了这个答案 This work as i want:我想要的这项工作:

在此处输入图像描述

But when I click in an inside textfield all the texfields focused:但是,当我单击内部文本字段时,所有 texfields 都集中在:

在此处输入图像描述

This is my code:这是我的代码:

import React from "react";
import ReactDOM from "react-dom";

import OutlinedDiv from "./OutlinedDiv";
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";

function App() {
  return (
    <div className="App">
      <OutlinedDiv label="DIV">
        <Grid container justify="center" alignItems="center" spacing={3}>
          <Grid item sm={4} xs={12}>
            <TextField label="Text1" variant="outlined" />
          </Grid>
          <Grid item sm={4} xs={12}>
            <TextField label="Text2" variant="outlined" />
          </Grid>
          <Grid item sm={4} xs={12}>
            <TextField label="Text3" variant="outlined" />
          </Grid>
          <Grid item sm={4} xs={12}>
            <TextField label="Text4" variant="outlined" />
          </Grid>
          <Grid item sm={4} xs={12}>
            <TextField label="Text5" variant="outlined" />
          </Grid>
          <Grid item sm={4} xs={12}>
            <TextField label="Text6" variant="outlined" />
          </Grid>
        </Grid>
      </OutlinedDiv>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

How I can achive this style and when click in an inside component only focus the selected component?我怎样才能实现这种风格,当点击内部组件时,只关注选定的组件?

A response with another approach and the similar solution for outlined div is welcome.欢迎使用另一种方法和概述 div 的类似解决方案做出回应。

Thanks in advance.提前致谢。

Below is an approach that does not leverage TextField or FormControl and thus can be safely used to wrap other inputs.下面是一种不利用TextFieldFormControl的方法,因此可以安全地用于包装其他输入。 This copies some styles from OutlinedInput and the InputLabel styles applied when within a FormControl .这会从OutlinedInput复制一些 styles 和在FormControl 中应用的 InputLabel styles

import React from "react";
import ReactDOM from "react-dom";
import InputLabel from "@material-ui/core/InputLabel";
import NotchedOutline from "@material-ui/core/OutlinedInput/NotchedOutline";
import { withStyles } from "@material-ui/core/styles";
import clsx from "clsx";

const styles = {
  root: {
    position: "relative",
    marginTop: "8px"
  },
  contentWrapper: {
    position: "relative"
  },
  content: {
    padding: "18.5px 14px"
  },
  inputLabel: {
    position: "absolute",
    left: 0,
    top: 0,
    // slight alteration to spec spacing to match visual spec result
    transform: "translate(0, 24px) scale(1)"
  },
  notchedOutline: {}
};

const LabelledOutline = ({ classes, id, label, children, className }) => {
  const [labelWidth, setLabelWidth] = React.useState(0);
  const labelRef = React.useRef(null);
  React.useEffect(() => {
    const labelNode = ReactDOM.findDOMNode(labelRef.current);
    setLabelWidth(labelNode != null ? labelNode.offsetWidth : 0);
  }, [label]);

  return (
    <div className={clsx(className, classes.root)}>
      <InputLabel
        ref={labelRef}
        htmlFor={id}
        variant="outlined"
        className={classes.inputLabel}
        shrink
      >
        {label}
      </InputLabel>
      <div className={classes.contentWrapper}>
        <div id={id} className={classes.content}>
          {children}
          <NotchedOutline
            className={classes.notchedOutline}
            notched
            labelWidth={labelWidth}
          />
        </div>
      </div>
    </div>
  );
};
export default withStyles(styles)(LabelledOutline);

And below is an example using it both without customization and once with customized colors for the label, outline, and content that changes on hover.下面是一个使用它的示例,既没有自定义也使用自定义 colors 用于 label、大纲和在 hover 上更改的内容。

import React from "react";
import ReactDOM from "react-dom";
import { withStyles } from "@material-ui/core/styles";

import LabelledOutline from "./LabelledOutline";

const CustomColorLabelledOutline = withStyles({
  root: {
    "& $notchedOutline": {
      borderColor: "purple"
    },
    "&:hover $notchedOutline": {
      borderColor: "orange"
    },
    "& $inputLabel": {
      color: "green"
    },
    "&:hover $inputLabel": {
      color: "blue"
    },
    "& $content": {
      color: "black"
    },
    "&:hover $content": {
      color: "purple"
    }
  },
  notchedOutline: {},
  inputLabel: {},
  content: {}
})(LabelledOutline);

function App() {
  return (
    <div>
      <LabelledOutline id="myID" label="My Label">
        My Content
      </LabelledOutline>
      <CustomColorLabelledOutline label="My Label">
        My Content with custom label and outline color
      </CustomColorLabelledOutline>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

编辑标注大纲

And the obligatory TS version (deeply inspired by @Ryan Cogswell's version):以及强制性的 TS 版本(深受@Ryan Cogswell 版本的启发):

import React, { ReactElement, ReactNode } from "react";
import InputLabel from "@material-ui/core/InputLabel";
import NotchedOutline from "@material-ui/core/OutlinedInput/NotchedOutline";
import { makeStyles, Theme } from "@material-ui/core/styles";
import clsx from "clsx";

const useStyles = makeStyles((theme: Theme) => ({
  root: {
    position: "relative",
    marginTop: "8px",
  },
  contentWrapper: {
    position: "relative",
  },
  content: {
    // padding: "18.5px 14px",
    padding: theme.spacing(1),
  },
  inputLabel: {
    position: "absolute",
    left: 0,
    top: 0,
    // slight alteration to spec spacing to match visual spec result
    transform: "translate(0, 24px) scale(1)",
  },
  notchedOutline: { borderRadius: theme.shape.borderRadius },
}));

interface Props {
  id: string;
  label: string;
  children: ReactNode;
  className?: string;
}

export default function Conftainer({ id, label, children, className }: Props): ReactElement {
  const [labelWidth, setLabelWidth] = React.useState(0);
  const labelRef = React.useRef(null);
  React.useEffect(() => {
    if (labelRef && labelRef.current && (labelRef.current as any).offsetWidth) {
      setLabelWidth((labelRef.current as any).offsetWidth);
    }
  }, [label]);
  const classes = useStyles();
  return (
    <div className={clsx(className, classes.root)}>
      <InputLabel
        ref={labelRef}
        htmlFor={id}
        variant="outlined"
        className={classes.inputLabel}
        shrink
      >
        {label}
      </InputLabel>
      <div className={classes.contentWrapper}>
        <div id={id} className={classes.content}>
          {children}
          <NotchedOutline className={classes.notchedOutline} notched labelWidth={labelWidth} />
        </div>
      </div>
    </div>
  );
}

(any edits to get rid of the any more than welcome) (任何编辑以摆脱any超过欢迎)

I don't have enough point to post a comment on @AntonOfTheWoods answer (I signed up SO today especially for this question).我没有足够的观点对@AntonOfTheWoods 的回答发表评论(我今天特别为这个问题注册了 SO)。

Just use const labelRef = React.useRef<HTMLLabelElement>(null);只需使用const labelRef = React.useRef<HTMLLabelElement>(null); and you should be able to get rid of the any你应该能够摆脱any

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM