为 React 搜索栏使用带有嵌套样式的样式化组件,尝试将两个不同的 SVG 放置在搜索栏的相对两侧

Posted

技术标签:

【中文标题】为 React 搜索栏使用带有嵌套样式的样式化组件,尝试将两个不同的 SVG 放置在搜索栏的相对两侧【英文标题】:Using Styled Components with nested styles for React Search Bar, trying to place two different SVGs at opposite sides of the search bar 【发布时间】:2020-08-21 17:48:36 【问题描述】:

我有一个使用 Styled Components 构建的 Search Bar React 组件。我有两个单独的 SVG,我试图添加到输入的内部,但在不同的侧面。

第一个 SVG 已正确定位以显示在搜索栏的左侧,并且只是一个静态 SVG。

第二个是一个 Circle X/Close 图标,我将它包裹在一个按钮中,以便向它传递一个清晰的输入 onClick 处理程序,我试图将此图标放在搜索栏的右侧,如下所示:

--------------------------
|????search              ⓧ |
--------------------------

我遇到的问题是 SVG 和我的 Input 字段都被设置为父 <div> 的子元素,它将嵌套样式传递给相应的元素,因此两个图标在左侧。

因此,我不知道如何分离两个 SVG 的样式,以便可以独立设置它们的样式。

我在这里有一个 CodeSandbox 来演示这个问题:

这是我当前的带有样式的组件:

import React,  useState  from "react";
import styled from "styled-components";

export const FilterTextbox = () => 
  const [text, setText] = useState("");
  const handleChange = (event: any) => 
    setText(event.target.value);
  ;
  const clearInput = () => 
    setText('');
  ;

  return (
    <form>
      <StyledInput className="inputWithIcon">
        <Input
          type="text"
          value=text
          onChange=handleChange
          placeholder="Search"
          onSubmit=e => 
            e.preventDefault();
          
        />
        <svg
          xmlns="http://www.w3.org/2000/svg"
          viewBox="0 0 24 24"
          
          
        >
          <path d="M 13.261719 14.867188 L 15.742188 17.347656 C 15.363281 18.070313 15.324219 18.789063 15.722656 19.1875 L 20.25 23.714844 C 20.820313 24.285156 22.0625 23.972656 23.015625 23.015625 C 23.972656 22.058594 24.285156 20.820313 23.714844 20.25 L 19.191406 15.722656 C 18.789063 15.324219 18.070313 15.363281 17.347656 15.738281 L 14.867188 13.261719 Z M 8.5 0 C 3.804688 0 0 3.804688 0 8.5 C 0 13.195313 3.804688 17 8.5 17 C 13.195313 17 17 13.195313 17 8.5 C 17 3.804688 13.195313 0 8.5 0 Z M 8.5 15 C 4.910156 15 2 12.089844 2 8.5 C 2 4.910156 4.910156 2 8.5 2 C 12.089844 2 15 4.910156 15 8.5 C 15 12.089844 12.089844 15 8.5 15 Z" />
        </svg>

        <button onClick=clearInput style= all: 'unset'>
          <svg    viewBox="0 0 24 24" version="1.1">
            <g id="surface1">
              <path d="M 12 1.546875 C 6.203125 1.546875 1.5 6.25 1.5 12.046875 C 1.5 17.84375 6.203125 22.546875 12 22.546875 C 17.796875 22.546875 22.5 17.84375 22.5 12.046875 C 22.5 6.25 17.796875 1.546875 12 1.546875 Z M 17.078125 15.585938 C 17.148438 15.65625 17.183594 15.75 17.183594 15.847656 C 17.183594 15.945312 17.148438 16.046875 17.078125 16.109375 L 16.0625 17.128906 C 15.988281 17.203125 15.894531 17.234375 15.800781 17.234375 C 15.707031 17.234375 15.609375 17.199219 15.539062 17.128906 L 12 13.585938 L 8.464844 17.132812 C 8.394531 17.207031 8.296875 17.242188 8.203125 17.242188 C 8.109375 17.242188 8.011719 17.203125 7.941406 17.132812 L 6.929688 16.117188 C 6.859375 16.046875 6.820312 15.953125 6.820312 15.851562 C 6.820312 15.753906 6.859375 15.65625 6.929688 15.589844 L 10.476562 12.027344 L 6.917969 8.511719 C 6.773438 8.367188 6.773438 8.128906 6.917969 7.984375 L 7.929688 6.964844 C 8 6.894531 8.09375 6.859375 8.195312 6.859375 C 8.292969 6.859375 8.386719 6.894531 8.457031 6.964844 L 12.003906 10.46875 L 15.554688 6.964844 C 15.625 6.894531 15.71875 6.859375 15.816406 6.859375 C 15.914062 6.859375 16.007812 6.894531 16.078125 6.964844 L 17.089844 7.984375 C 17.234375 8.128906 17.234375 8.367188 17.089844 8.511719 L 13.53125 12.027344 Z M 17.078125 15.585938 "/>
            </g>
          </svg>
        </button>
      </StyledInput>
    </form>
  );
;

const Input = styled.input`
  height: 50px;
  font-size: 25px;
  width: 100%;
  border: 2px solid #aaa;
  border-radius: 4px;
  margin: 8px 0;
  outline: none;
  padding: 8px;
  box-sizing: border-box;
  transition: 0.3s;
  padding-left: 50px;
  cursor: pointer;

  :focus 
    border-color: dodgerBlue;
    box-shadow: 0 0 8px 0 dodgerBlue;
  
`;

const StyledInput = styled.div`
  svg 
    position: absolute;
    left: 0;
    top: 8px;
    padding: 9px 8px;
    fill: black;
    transition: 0.3s;
  

  input:focus + svg 
    fill: dodgerBlue;
  

  &.inputWithIcon 
    position: relative;
  
`;

【问题讨论】:

【参考方案1】:

只需将StyledInput 视为具有左侧图标和右侧带有图标的按钮的容器并设置它们的样式。 IMO,实际的input 应该只关注自己,容器应该确定其他人的风格(显然不包括依赖于输入的焦点)。 你可以这样做:

https://codesandbox.io/s/broken-shadow-c5wxp

import React,  useState  from "react";
import styled from "styled-components";

export const FilterTextbox = () => 
  const [text, setText] = useState("");
  const handleChange = (event: any) => 
    setText(event.target.value);
  ;
  const clearInput = () => 
    setText("");
  ;

  return (
    <form>
      <StyledInput className="inputWithIcon">
        <Input
          type="text"
          value=text
          onChange=handleChange
          placeholder="Search"
          onSubmit=e => 
            e.preventDefault();
          
        />
        <div className="left-icon">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            
            
          >
            <path d="M 13.261719 14.867188 L 15.742188 17.347656 C 15.363281 18.070313 15.324219 18.789063 15.722656 19.1875 L 20.25 23.714844 C 20.820313 24.285156 22.0625 23.972656 23.015625 23.015625 C 23.972656 22.058594 24.285156 20.820313 23.714844 20.25 L 19.191406 15.722656 C 18.789063 15.324219 18.070313 15.363281 17.347656 15.738281 L 14.867188 13.261719 Z M 8.5 0 C 3.804688 0 0 3.804688 0 8.5 C 0 13.195313 3.804688 17 8.5 17 C 13.195313 17 17 13.195313 17 8.5 C 17 3.804688 13.195313 0 8.5 0 Z M 8.5 15 C 4.910156 15 2 12.089844 2 8.5 C 2 4.910156 4.910156 2 8.5 2 C 12.089844 2 15 4.910156 15 8.5 C 15 12.089844 12.089844 15 8.5 15 Z" />
          </svg>
        </div>

        <button className="right-icon" onClick=clearInput>
          <svg   viewBox="0 0 24 24" version="1.1">
            <g id="surface1">
              <path d="M 12 1.546875 C 6.203125 1.546875 1.5 6.25 1.5 12.046875 C 1.5 17.84375 6.203125 22.546875 12 22.546875 C 17.796875 22.546875 22.5 17.84375 22.5 12.046875 C 22.5 6.25 17.796875 1.546875 12 1.546875 Z M 17.078125 15.585938 C 17.148438 15.65625 17.183594 15.75 17.183594 15.847656 C 17.183594 15.945312 17.148438 16.046875 17.078125 16.109375 L 16.0625 17.128906 C 15.988281 17.203125 15.894531 17.234375 15.800781 17.234375 C 15.707031 17.234375 15.609375 17.199219 15.539062 17.128906 L 12 13.585938 L 8.464844 17.132812 C 8.394531 17.207031 8.296875 17.242188 8.203125 17.242188 C 8.109375 17.242188 8.011719 17.203125 7.941406 17.132812 L 6.929688 16.117188 C 6.859375 16.046875 6.820312 15.953125 6.820312 15.851562 C 6.820312 15.753906 6.859375 15.65625 6.929688 15.589844 L 10.476562 12.027344 L 6.917969 8.511719 C 6.773438 8.367188 6.773438 8.128906 6.917969 7.984375 L 7.929688 6.964844 C 8 6.894531 8.09375 6.859375 8.195312 6.859375 C 8.292969 6.859375 8.386719 6.894531 8.457031 6.964844 L 12.003906 10.46875 L 15.554688 6.964844 C 15.625 6.894531 15.71875 6.859375 15.816406 6.859375 C 15.914062 6.859375 16.007812 6.894531 16.078125 6.964844 L 17.089844 7.984375 C 17.234375 8.128906 17.234375 8.367188 17.089844 8.511719 L 13.53125 12.027344 Z M 17.078125 15.585938 " />
            </g>
          </svg>
        </button>
      </StyledInput>
    </form>
  );
;

const Input = styled.input`
  height: 50px;
  font-size: 25px;
  width: 100%;
  border: 2px solid #aaa;
  border-radius: 4px;
  margin: 8px 0;
  outline: none;
  padding: 8px;
  box-sizing: border-box;
  transition: 0.3s;
  padding-left: 50px;
  cursor: pointer;

  &:focus 
    border-color: dodgerBlue;
    box-shadow: 0 0 8px 0 dodgerBlue;
  

  :focus + .left-icon
    svg
      fill: dodgerBlue;
    
  

`;

const StyledInput = styled.div`
  &.inputWithIcon 
    position: relative;
  

  .left-icon 
    position: absolute;
    left: 5px;
    top: 50%;
    transform: translateY(-50%);
    svg 
      fill: black;
      transition: 0.3s;
    
  

  button.right-icon 
    background:none;
    border:none;
    position: absolute;
    right: 5px;
    top: 50%;
    transform: translateY(-50%);
    svg 
      fill: black;
      transition: 0.3s;
    
  
`;

希望这会有所帮助!

【讨论】:

@Josh 哈哈。不用担心:)【参考方案2】:

StyledInput 样式中的 svg 样式也影响了按钮内部的 svg,修复了这个前缀为 &amp; &gt; 的 svg 样式


import React,  useState  from "react";
import styled from "styled-components";

export const FilterTextbox = () => 
  const [text, setText] = useState("");
  const handleChange = (event: any) => 
    setText(event.target.value);
  ;
  const clearInput = () => 
    setText("");
  ;
  return (
    <form>
      <StyledInput className="inputWithIcon">
        <Input
          type="text"
          value=text
          onChange=handleChange
          placeholder="Search"
          onSubmit=e => 
            e.preventDefault();
          
        />
        <svg
          xmlns="http://www.w3.org/2000/svg"
          viewBox="0 0 24 24"
          
          
        >
          <path d="M 13.261719 14.867188 L 15.742188 17.347656 C 15.363281 18.070313 15.324219 18.789063 15.722656 19.1875 L 20.25 23.714844 C 20.820313 24.285156 22.0625 23.972656 23.015625 23.015625 C 23.972656 22.058594 24.285156 20.820313 23.714844 20.25 L 19.191406 15.722656 C 18.789063 15.324219 18.070313 15.363281 17.347656 15.738281 L 14.867188 13.261719 Z M 8.5 0 C 3.804688 0 0 3.804688 0 8.5 C 0 13.195313 3.804688 17 8.5 17 C 13.195313 17 17 13.195313 17 8.5 C 17 3.804688 13.195313 0 8.5 0 Z M 8.5 15 C 4.910156 15 2 12.089844 2 8.5 C 2 4.910156 4.910156 2 8.5 2 C 12.089844 2 15 4.910156 15 8.5 C 15 12.089844 12.089844 15 8.5 15 Z" />
        </svg>
        <button onClick=clearInput>
          <svg   viewBox="0 0 24 24" version="1.1">
            <g id="surface1">
              <path d="M 12 1.546875 C 6.203125 1.546875 1.5 6.25 1.5 12.046875 C 1.5 17.84375 6.203125 22.546875 12 22.546875 C 17.796875 22.546875 22.5 17.84375 22.5 12.046875 C 22.5 6.25 17.796875 1.546875 12 1.546875 Z M 17.078125 15.585938 C 17.148438 15.65625 17.183594 15.75 17.183594 15.847656 C 17.183594 15.945312 17.148438 16.046875 17.078125 16.109375 L 16.0625 17.128906 C 15.988281 17.203125 15.894531 17.234375 15.800781 17.234375 C 15.707031 17.234375 15.609375 17.199219 15.539062 17.128906 L 12 13.585938 L 8.464844 17.132812 C 8.394531 17.207031 8.296875 17.242188 8.203125 17.242188 C 8.109375 17.242188 8.011719 17.203125 7.941406 17.132812 L 6.929688 16.117188 C 6.859375 16.046875 6.820312 15.953125 6.820312 15.851562 C 6.820312 15.753906 6.859375 15.65625 6.929688 15.589844 L 10.476562 12.027344 L 6.917969 8.511719 C 6.773438 8.367188 6.773438 8.128906 6.917969 7.984375 L 7.929688 6.964844 C 8 6.894531 8.09375 6.859375 8.195312 6.859375 C 8.292969 6.859375 8.386719 6.894531 8.457031 6.964844 L 12.003906 10.46875 L 15.554688 6.964844 C 15.625 6.894531 15.71875 6.859375 15.816406 6.859375 C 15.914062 6.859375 16.007812 6.894531 16.078125 6.964844 L 17.089844 7.984375 C 17.234375 8.128906 17.234375 8.367188 17.089844 8.511719 L 13.53125 12.027344 Z M 17.078125 15.585938 " />
            </g>
          </svg>
        </button>
      </StyledInput>
    </form>
  );
;

const Input = styled.input`
  height: 50px;
  font-size: 25px;
  width: 100%;
  border: 2px solid #aaa;
  border-radius: 4px;
  margin: 8px 0;
  outline: none;
  padding: 8px;
  box-sizing: border-box;
  transition: 0.3s;
  padding-left: 50px;

  :focus 
    border-color: dodgerBlue;
    box-shadow: 0 0 8px 0 dodgerBlue;
  
`;

const StyledInput = styled.div`
  position: relative;
  & > svg 
    position: absolute;
    left: 0;
    top: 8px;
    padding: 9px 8px;
    fill: black;
    transition: 0.3s;
  

  input:focus + svg 
    fill: dodgerBlue;
  
  button 
    position: absolute;
    right: 0;
    top: 8px;
    top: 0;
    background-color: transparent;
    top: 16px;
    border: none;
  

  &.inputWithIcon 
    position: relative;
  
`;

【讨论】:

以上是关于为 React 搜索栏使用带有嵌套样式的样式化组件,尝试将两个不同的 SVG 放置在搜索栏的相对两侧的主要内容,如果未能解决你的问题,请参考以下文章

警告:道具 `className` 不匹配。当使用带有语义-ui-react 的样式化组件时

如何在使用 TypeScript 的 create-react-app 中使用带有 babel 插件的样式化组件?

使用 Styled-Components 在 React Bootstrap 中覆盖嵌套样式

如何在 react-native-element 中获得这种搜索栏样式?

无法使用带有样式组件的关键帧设置嵌套动画的样式

使用带有 typescript 的样式化组件“as”prop