Дочерний элемент Flex исчезает при очень малой ширине

#javascript #html #css #reactjs #flexbox

#javascript #HTML #css #reactjs #flexbox

Вопрос:

Я создаю компонент изменения размера с помощью 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 элемент) просто исчезает. Итак, если я отпущу мышь в этой позиции, я не смогу снова развернуть столбец, поскольку нет захвата для захвата (он исчез).

Другими словами, если ему по какой-то причине нужно уменьшить столбец, он не может увеличить его снова, поскольку нет захвата для захвата.

Как я могу сохранить видимость своего захвата на любой возможной ширине, позволяя пользователю изменять размер столбца при любых обстоятельствах?

Комментарии:

1. это из-за границы размером 10 пикселей, которую вы добавляете к элементу (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>  

Комментарии:

1. Спасибо. position: sticky спас мой день.

2. @Mendes добавил другой способ 😉

Ответ №2:

Простым решением может быть небольшая доработка вашего CSS, чтобы ваши элементы захвата располагались с absolute , выравнивались и имели размер по правому краю и высоте родительского элемента .cell-container :

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

Вы также должны явно установить min-width of .cell-container в соответствии с шириной захвата, чтобы она все еще была видна, когда контейнер полностью свернут:

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

Я обновил ваш код с помощью этих изменений, которые работают во фрагменте ниже:

 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>