自动调整CSS下拉框大小以适合其最大元素

时间:2019-05-27 16:51:51

标签: css reactjs

我想从始终具有其最宽元素宽度的项目列表中进行选择。选中的项目是始终显示的项目,其他选项则显示在悬停上。

这是一个简单的CSS下拉列表,理想情况下,我希望看到纯CSS解决方案。由于我正在使用React,并且此下拉列表是一个组件,因此可以接受js解决方案(如果可能,则不使用jQuery或其他库)。

const Dropdown = (props) => (
	<div className="dropdown">
	  <div className="dropdown-item">{props.active}</div>
    <div className="dropdown-body">
      {props.items
        .filter(x => x !== props.active)
        .map(x => <div className="dropdown-item">{x}</div>)}
    </div>
	</div>
)

var items = [
	"abc", "abcdcdssd", "a"
]

ReactDOM.render(
	<div>Hello <Dropdown items={items} active={"abc"} /> world.</div>,
  document.querySelector("#app")
)
.dropdown {
  display: inline-block;
  background-color: blue;
  text-align: center;
}

.dropdown .dropdown-item {
  background-color: red;
  width: auto;
  padding: 0 6px;
}

.dropdown .dropdown-body {
  display: none;
  position: absolute;
  z-index: 1000;
}

.dropdown:hover .dropdown-body {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

在上面的示例中,我希望"abc"元素的宽度大于最大元素"abcdcdssd"的宽度。

1 个答案:

答案 0 :(得分:2)

纯CSS解决方案

一个纯CSS解决方案是给您的容器一个width: auto并在您的商品上使用visibility样式而不是display来隐藏它们:

const Dropdown = (props) => (
	<div className="dropdown">
	  <div className="dropdown-item">{props.active}</div>
    <div className="dropdown-body">
      {props.items
        .filter(x => x !== props.active)
        .map(x => <div className="dropdown-item">{x}</div>)}
    </div>
	</div>
)

var items = [
	"abc", "abcdcdssd", "a"
]

ReactDOM.render(
	<div>Hello <Dropdown items={items} active={"abc"} /> world.</div>,
  document.querySelector("#app")
)

var items = [
	"abc", "abcdcdssd", "a"
]

ReactDOM.render(
	<div>Hello <Dropdown items={items} active={"abc"} /> world.</div>,
  document.querySelector("#app")
)
.dropdown {
  display: inline-block;
  text-align: center;
  vertical-align: top;
  width: auto;
}

.dropdown .dropdown-item {
  background-color: red;
  padding: 0 6px;
}

.dropdown .dropdown-body {
  visibility: hidden;
  z-index: 1000;
}

.dropdown:hover .dropdown-body {
  visibility: visible;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="app"></div>

需要注意的是,因为只有在选择了文本后,这些项目才会被隐藏,所以隐藏的项目也会被选中。

JS解决方案

您可以在初始渲染后测量下拉实体的宽度,并将其应用于活动的下拉项目。为此,您最初需要使用visibility: hidden而不是display: none,因为只能测量隐藏元素的宽度。您可以在对其进行初步测量后立即将其隐藏。

以下示例使用了需要版本>16.8的react钩子,但也可以使用基于componentDidMount的基于类的组件来实现。

const {useRef, useState, useLayoutEffect} = React;

const Dropdown = props => {
    const bodyRef = useRef();
    const [bodyWidth, setWidth] = useState(null);
    const [itemsHidden, setItemsHidden] = useState(false);
    useLayoutEffect(() => {
        setWidth(bodyRef.current.clientWidth);
        setItemsHidden(true);
    }, []);

    return (
        <div style={{width: bodyWidth || 'auto'}} className="dropdown">
            <div className="dropdown-item">{props.active}</div>
            <div ref={bodyRef} className={`dropdown-body${itemsHidden ? ' hidden' : ''}`}>
                {props.items
                    .filter(x => x !== props.active)
                    .map((x, idx) => (
                        <div key={idx} className="dropdown-item">{x}</div>
                    ))}
            </div>
        </div>
    );
};

var items = [
	"abc", "abcdcdssd", "a"
]

ReactDOM.render(
	<div>Hello <Dropdown items={items} active={"abc"} /> world.</div>,
  document.querySelector("#app")
)
.dropdown {
    display: inline-block;
    background-color: blue;
    text-align: center;
}

.dropdown .dropdown-item {
    background-color: red;
    width: auto;
    padding: 0 6px;
}

.dropdown .dropdown-body {
    position: absolute;
    z-index: 1000;
}

.dropdown .dropdown-body.hidden {
  display: none;
  position: absolute;
  z-index: 1000;
}

.dropdown:hover .dropdown-body {
    display: block;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="app"></div>