Flex 子项在非常小的宽度上消失

Posted

技术标签:

【中文标题】Flex 子项在非常小的宽度上消失【英文标题】:Flex child item disappear on very small widths 【发布时间】:2019-09-13 04:35:30 【问题描述】:

我正在使用 ReactJS 构建一个调整大小的组件。代码如下:

class Cell extends React.Component 
  handleMouseDown = event => 
    this.props.onMouseDown(this.props.index, event);
  ;

  render() 
    let verticalGrip = ( <
      div onMouseDown = 
        this.handleMouseDown
      
      className = "cell-vertical-grip" / >
    );

    return ( <
      div className = "cell-container"
      style = 
        
          width: this.props.widths[this.props.index]
        
       >
      <
      div className = "cell-content"
      style = 
        
          border: "10px solid transparent"
        
       >
      
        "WIDTH " + this.props.widths[this.props.index]
       <
      /div> 
        verticalGrip
       <
      /div>
    );
  


class Test extends React.Component 
  state = 
    widths: [100, 100, 100, 100],
    baseWidths: [100, 100, 100, 100],
    xBase: 0,
    resizeIndex: null
  ;

  handleMouseDown = (index, event) => 
    console.log("MouseDown: index: " + index + ", pageX: " + event.pageX);

    this.setState(
      xBase: event.pageX,
      resizing: true,
      resizeIndex: index
    );
  ;

  handleMouseMove = event => 
    if (this.state.resizing) 

      let delta = this.state.xBase - event.pageX;

      console.log("MouseMove " + delta);

      let widths = this.state.widths.slice();
      widths[this.state.resizeIndex] = this.state.baseWidths[this.state.resizeIndex] - delta;

      this.setState(
        widths: widths
      );
    
  ;

  handleMouseUp = event => 
    console.log("MouseUp");

    this.setState(
      resizing: false,
      resizeIndex: null
    );
  ;

  render() 
    return ( <
      div className = "test-container"
      onMouseMove = 
        this.handleMouseMove
      
      onMouseUp = 
        this.handleMouseUp
       >
      <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        0
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        1
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        2
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        3
      
      /> <
      /div>
    );
  


// Render it
ReactDOM.render( <
  Test / > ,
  document.body
);
.test-container 
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: row;
  background-color: cyan;


.cell-container 
  width: 100%;
  height: 100px;
  display: flex;
  flex-direction: row;
  background-color: grey;
  border: 1px solid black;
  overflow-y: hidden;
  overflow-x: hidden;


.cell-content 
  align-self: center;
  flex-shrink: 1;
  font-size: 12px;
  overflow-y: hidden;
  overflow-x: hidden;
  background-color: white;


.cell-vertical-grip 
  flex-shrink: 0;
  margin-left: auto;
  width: 3px;
  min-width: 3px;
  cursor: ew-resize;
  background-color: blue;
<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>

verticalGrip 是您抓取要调整大小的列的位置。

一切正常,但是当我将任何列的宽度调整为小于20px 时,就会出现我的问题。在那种情况下,我的蓝色手柄(verticalGrip item)就消失了。因此,如果我在该位置释放鼠标,我将无法再次展开该列,因为没有抓握(它已消失)。

换句话说,如果他出于某种原因需要缩小一列,他不能再次增长它,因为没有抓地力。

如何让我的夹点在所有可能的宽度上都可见,允许用户在任何情况下调整列的大小?

【问题讨论】:

这是因为您要添加到元素的 10px 边框 (2x10px = 20px) 【参考方案1】:

一个想法是使您的元素在右侧具有粘性,并且由于您应用到元素的边框而导致溢出时它不会消失。

class Cell extends React.Component 
  handleMouseDown = event => 
    this.props.onMouseDown(this.props.index, event);
  ;

  render() 
    let verticalGrip = ( <
      div onMouseDown = 
        this.handleMouseDown
      
      className = "cell-vertical-grip" / >
    );

    return ( <
      div className = "cell-container"
      style = 
        
          width: this.props.widths[this.props.index]
        
       >
      <
      div className = "cell-content"
      style = 
        
          border: "10px solid transparent"
        
       >
      
        "WIDTH " + this.props.widths[this.props.index]
       <
      /div> 
        verticalGrip
       <
      /div>
    );
  


class Test extends React.Component 
  state = 
    widths: [100, 100, 100, 100],
    baseWidths: [100, 100, 100, 100],
    xBase: 0,
    resizeIndex: null
  ;

  handleMouseDown = (index, event) => 
    console.log("MouseDown: index: " + index + ", pageX: " + event.pageX);

    this.setState(
      xBase: event.pageX,
      resizing: true,
      resizeIndex: index
    );
  ;

  handleMouseMove = event => 
    if (this.state.resizing) 

      let delta = this.state.xBase - event.pageX;

      console.log("MouseMove " + delta);

      let widths = this.state.widths.slice();
      widths[this.state.resizeIndex] = this.state.baseWidths[this.state.resizeIndex] - delta;

      this.setState(
        widths: widths
      );
    
  ;

  handleMouseUp = event => 
    console.log("MouseUp");

    this.setState(
      resizing: false,
      resizeIndex: null
    );
  ;

  render() 
    return ( <
      div className = "test-container"
      onMouseMove = 
        this.handleMouseMove
      
      onMouseUp = 
        this.handleMouseUp
       >
      <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        0
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        1
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        2
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        3
      
      /> <
      /div>
    );
  


// Render it
ReactDOM.render( <
  Test / > ,
  document.body
);
.test-container 
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: row;
  background-color: cyan;


.cell-container 
  width: 100%;
  height: 100px;
  display: flex;
  flex-direction: row;
  background-color: grey;
  border: 1px solid black;
  overflow-y: hidden;
  overflow-x: hidden;


.cell-content 
  align-self: center;
  flex-shrink: 1;
  font-size: 12px;
  overflow-y: hidden;
  overflow-x: hidden;
  background-color: white;


.cell-vertical-grip 
  flex-shrink: 0;
  margin-left: auto;
  width: 3px;
  min-width: 3px;
  cursor: ew-resize;
  background-color: blue;
  
  position:sticky;
  right:0;
<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>

或者您可以考虑另一种想法,而不是像轮廓或框阴影这样不会影响元素宽度的边框,并且您将获得相同的视觉输出:

class Cell extends React.Component 
  handleMouseDown = event => 
    this.props.onMouseDown(this.props.index, event);
  ;

  render() 
    let verticalGrip = ( <
      div onMouseDown = 
        this.handleMouseDown
      
      className = "cell-vertical-grip" / >
    );

    return ( <
      div className = "cell-container"
      style = 
        
          width: this.props.widths[this.props.index]
        
       >
      <
      div className = "cell-content"
      style = 
        
          outline: "10px solid #fff"
        
       >
      
        "WIDTH " + this.props.widths[this.props.index]
       <
      /div> 
        verticalGrip
       <
      /div>
    );
  


class Test extends React.Component 
  state = 
    widths: [100, 100, 100, 100],
    baseWidths: [100, 100, 100, 100],
    xBase: 0,
    resizeIndex: null
  ;

  handleMouseDown = (index, event) => 
    console.log("MouseDown: index: " + index + ", pageX: " + event.pageX);

    this.setState(
      xBase: event.pageX,
      resizing: true,
      resizeIndex: index
    );
  ;

  handleMouseMove = event => 
    if (this.state.resizing) 

      let delta = this.state.xBase - event.pageX;

      console.log("MouseMove " + delta);

      let widths = this.state.widths.slice();
      widths[this.state.resizeIndex] = this.state.baseWidths[this.state.resizeIndex] - delta;

      this.setState(
        widths: widths
      );
    
  ;

  handleMouseUp = event => 
    console.log("MouseUp");

    this.setState(
      resizing: false,
      resizeIndex: null
    );
  ;

  render() 
    return ( <
      div className = "test-container"
      onMouseMove = 
        this.handleMouseMove
      
      onMouseUp = 
        this.handleMouseUp
       >
      <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        0
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        1
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        2
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        3
      
      /> <
      /div>
    );
  


// Render it
ReactDOM.render( <
  Test / > ,
  document.body
);
.test-container 
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: row;
  background-color: cyan;


.cell-container 
  width: 100%;
  height: 100px;
  display: flex;
  flex-direction: row;
  background-color: grey;
  border: 1px solid black;
  overflow-y: hidden;
  overflow-x: hidden;

/*to push the element so we can see the outline*/
.cell-container:before 
  content:"";
  width:10px;


.cell-content 
  align-self: center;
  flex-shrink: 1;
  font-size: 12px;
  overflow-y: hidden;
  overflow-x: hidden;
  background-color: white;


.cell-vertical-grip 
  flex-shrink: 0;
  margin-left: auto;
  width: 3px;
  min-width: 3px;
  cursor: ew-resize;
  background-color: blue;
<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>

【讨论】:

谢谢。 position: sticky 拯救了我的一天。 @Mendes 添加了另一种方式 ;)【参考方案2】:

一个简单的解决方案可能是稍微修改您的 CSS,以便您的抓取器元素使用 absolute 定位,对齐并调整大小到父 .cell-container 的右边缘和高度:

.cell-vertical-grip 
  /* Add this */
  position:absolute;
  top:0;
  height:100%;
  right:0;

您还可以明确设置 .cell-containermin-width 以匹配夹具宽度,以便在容器完全折叠时仍然可见:

.cell-container 
  /* Add this */
  min-width:3px;
  position:relative;

我已使用以下 sn-p 中的这些更改更新了您的代码:

class Cell extends React.Component 
  handleMouseDown = event => 
    this.props.onMouseDown(this.props.index, event);
  ;

  render() 
    let verticalGrip = ( <
      div onMouseDown = 
        this.handleMouseDown
      
      className = "cell-vertical-grip" / >
    );

    return ( <
      div className = "cell-container"
      style = 
        
          width: this.props.widths[this.props.index]
        
       >
      <
      div className = "cell-content"
      style = 
        
          border: "10px solid transparent"
        
       >
      
        "WIDTH " + this.props.widths[this.props.index]
       <
      /div> 
        verticalGrip
       <
      /div>
    );
  


class Test extends React.Component 
  state = 
    widths: [100, 100, 100, 100],
    baseWidths: [100, 100, 100, 100],
    xBase: 0,
    resizeIndex: null
  ;

  handleMouseDown = (index, event) => 
    console.log("MouseDown: index: " + index + ", pageX: " + event.pageX);

    this.setState(
      xBase: event.pageX,
      resizing: true,
      resizeIndex: index
    );
  ;

  handleMouseMove = event => 
    if (this.state.resizing) 

      let delta = this.state.xBase - event.pageX;

      console.log("MouseMove " + delta);

      let widths = this.state.widths.slice();
      widths[this.state.resizeIndex] = this.state.baseWidths[this.state.resizeIndex] - delta;

      this.setState(
        widths: widths
      );
    
  ;

  handleMouseUp = event => 
    console.log("MouseUp");

    this.setState(
      resizing: false,
      resizeIndex: null
    );
  ;

  render() 
    return ( <
      div className = "test-container"
      onMouseMove = 
        this.handleMouseMove
      
      onMouseUp = 
        this.handleMouseUp
       >
      <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        0
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        1
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        2
      
      /> <
      Cell widths = 
        this.state.widths
      
      onMouseDown = 
        this.handleMouseDown
      
      index = 
        3
      
      /> <
      /div>
    );
  


// Render it
ReactDOM.render( <
  Test / > ,
  document.body
);
.test-container 
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: row;
  background-color: cyan;


.cell-container 
  width: 100%;
  height: 100px;
  display: flex;
  flex-direction: row;
  background-color: grey;
  border: 1px solid black;
  overflow-y: hidden;
  overflow-x: hidden;

  /* Add this */
  min-width:3px;
  position:relative;


.cell-content 
  align-self: center;
  flex-shrink: 1;
  font-size: 12px;
  overflow-y: hidden;
  overflow-x: hidden;
  background-color: white;


.cell-vertical-grip 
  flex-shrink: 0;
  margin-left: auto;
  width: 3px;
  min-width: 3px;
  cursor: ew-resize;
  background-color: blue;

  /* Add this */
  position:absolute;
  top:0;
  height:100%;
  right:0;
<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>

【讨论】:

以上是关于Flex 子项在非常小的宽度上消失的主要内容,如果未能解决你的问题,请参考以下文章

在 ActionScript 和 Flex 中计算文本宽度

Flex-grow 没有按预期工作(弹性项目没有我期望的宽度)

div中子元素input设置flex无效

div中子元素input设置flex无效

如何将 flex-container 设置为其 flex-items 的宽度?

等宽布局和flex