Recommended way to have drawer resizable?

前端 未结 4 1508
故里飘歌
故里飘歌 2021-01-05 16:00

I would like to have the material ui drawer\'s width resizable through a draggable handle. My current approach is to have a mousevent listener on the whole app which checks

相关标签:
4条回答
  • 2021-01-05 16:24

    You can do that with css only, if that fits your need. It's the simplest solution. Look mom, no javascript.

    .resizable {
      height: 150px;
      width: 150px;
      border: 1px solid #333;
      resize: horizontal;
      overflow: auto;
    }
    <div class="resizable"></div>

    Reference on MDN

    0 讨论(0)
  • 2021-01-05 16:28

    I would like to add an answer that is more up to date using React Hooks.

    You can do it like this, then:

    CSS:

    sidebar-dragger: {
      width: '5px',
      cursor: 'ew-resize',
      padding: '4px 0 0',
      borderTop: '1px solid #ffffd',
      position: 'absolute',
      top: 0,
      left: 0,
      bottom: 0,
      zIndex: '100',
      backgroundColor: '#f4f7f9'
    }
    

    React (using hooks with refs and states)

    let isResizing = null;
    
    function ResizeableSidebar (props) {
      const sidebarPanel = React.useRef('sidebarPanel');
      const cbHandleMouseMove = React.useCallback(handleMousemove, []);
      const cbHandleMouseUp = React.useCallback(handleMouseup, []);
    
      function handleMousedown (e) {
        e.stopPropagation();
        e.preventDefault();
        // we will only add listeners when needed, and remove them afterward
        document.addEventListener('mousemove', cbHandleMouseMove);
        document.addEventListener('mouseup', cbHandleMouseUp);
        isResizing = true;
      };
    
      function handleMousemove (e) {
        if (!isResizing) {
          return;
        }
    
        let offsetRight =
          document.body.offsetWidth - (e.clientX - document.body.offsetLeft);
        let minWidth = 50;
        if (offsetRight > minWidth) {
          let curSize = offsetRight - 60;
          // using a ref instead of state will be way faster
          sidebarPanel.current.style.width = curSize + 'px';
        }
      };
    
      function handleMouseup (e) {
        if (!isResizing) {
          return;
        }
        isResizing = false;
        document.removeEventListener('mousemove', cbHandleMouseMove);
        document.removeEventListener('mouseup', cbHandleMouseUp);
      };
    
      return <div className="sidebar-container">
        <div
          className="sidebar-dragger"
          onMouseDown={handleMousedown}
        />
        <div>
          Your stuff goes here
        </div>
      </div>;
    }
    
    0 讨论(0)
  • 2021-01-05 16:33

    You can use indicator dragger with mousedown on it.

    Here for example

    // styles
    dragger: {
      width: '5px',
      cursor: 'ew-resize',
      padding: '4px 0 0',
      borderTop: '1px solid #ffffd',
      position: 'absolute',
      top: 0,
      left: 0,
      bottom: 0,
      zIndex: '100',
      backgroundColor: '#f4f7f9'
    }
    
    ...
    
    state = {
      isResizing: false,
      lastDownX: 0,
      newWidth: {}
    };
    
    handleMousedown = e => {
      this.setState({ isResizing: true, lastDownX: e.clientX });
    };
    
    handleMousemove = e => {
      // we don't want to do anything if we aren't resizing.
      if (!this.state.isResizing) {
        return;
      }
    
      let offsetRight =
        document.body.offsetWidth - (e.clientX - document.body.offsetLeft);
      let minWidth = 50;
      let maxWidth = 600;
      if (offsetRight > minWidth && offsetRight < maxWidth) {
        this.setState({ newWidth: { width: offsetRight } });
      }
    };
    
    handleMouseup = e => {
      this.setState({ isResizing: false });
    };
    
    componentDidMount() {
      document.addEventListener('mousemove', e => this.handleMousemove(e));
      document.addEventListener('mouseup', e => this.handleMouseup(e));
    }
    
    ...
    
    <Drawer
      variant="permanent"
      open
      anchor={'right'}
      classes={{
        paper: classes.drawerPaper
      }}
      PaperProps={{ style: this.state.newWidth }}
    >
      <div
        id="dragger"
        onMouseDown={event => {
          this.handleMousedown(event);
        }}
        className={classes.dragger}
      />
      {drawer}
    </Drawer>
    

    The idea is, when click the dragger, it will resize width Drawer followed mouse move.

    Play DEMO.

    0 讨论(0)
  • 2021-01-05 16:44

    Just use a synthetic event on your handle element. That way, you can avoid the messiness/performance costs of having a universal event listener. Something like the following:

    render() {
         return (
           <div onMouseDown={this.yourResizeFunc}>
           </div>
      );
    }
    
    0 讨论(0)
提交回复
热议问题