Change width proportions of two blocks with a slider

前端 未结 1 391
臣服心动
臣服心动 2020-12-21 02:40

I\'m trying to design a component in which you could change the width proportions of two blocks by moving a slider left and right:

codpen and demo:

相关标签:
1条回答
  • 2020-12-21 03:41

    You can adjust your flexbox along with resize - the downside is that the slider its not very customizeable:

    • add resize: horizontal to one of the flex items
    • add flex: 1 to the other flex item (so that this flex item will adjust automatically in response to the changing width of the other flex item as it is resized)

    See demo below:

    .outer {
      display: flex;
      flex-direction: row;
    }
    
    .block {
      height: 100px;
      width: 50%; /* 50% would suffice*/
    }
    
    .block-1 {
      background-color: red;
      resize: horizontal; /* resize horizontal */
      overflow: hidden; /* resize works for overflow other than visible */
    }
    
    .block-2 {
      background-color: green;
      flex: 1; /* adjust automatically */
    }
    <div id="app">
      <div class="outer">
        <div class="block block-1">
          Block 1
        </div>
        <div class="block block-2">
          Block 2
        </div>
      </div>
    </div>


    So we'll use vanilla JS instead of the resize solution above:

    • use a mousedown listener that registers a mousemove listener that updates the block-1 width (and reset the mouseup event)
    • also consider min-width: 0 to override min-width: auto of the block-2 element

    See demo below:

    let block = document.querySelector(".block-1"),
      slider = document.querySelector(".slider");
    
    slider.onmousedown = function dragMouseDown(e) {
      let dragX = e.clientX;
      document.onmousemove = function onMouseMove(e) {
        block.style.width = block.offsetWidth + e.clientX - dragX + "px";
        dragX = e.clientX;
      }
      // remove mouse-move listener on mouse-up
      document.onmouseup = () => document.onmousemove = document.onmouseup = null;
    }
    .outer {
      display: flex;
      flex-direction: row;
    }
    
    .block {
      height: 100px;
      width: 50%; /* 50% would suffice*/
    }
    
    .block-1 {
      background-color: red;
    }
    
    .block-2 {
      background-color: green;
      flex: 1; /* adjust automatically */
      min-width: 0; /* allow flexing beyond auto width */
      overflow: hidden; /* hide overflow on small width */
    }
    
    .slider {
      line-height: 100%;
      width: 10px;
      background-color: #dee2e6;
      border: none;
      cursor: col-resize;
      user-select: none; /* disable selection */
      text-align: center;
    }
    <div id="app">
      <div class="outer">
        <div class="block block-1">
          Block 1
        </div>
        <div class="slider">
          S<br>l<br>i<br>d<br>e<br>r
        </div>
        <div class="block block-2">
          Block 2
        </div>
      </div>
    </div>


    Solution

    You can adapt the above into Vue easily without using any custom Vue plugins for this - the changes are:

    • @mousedown listener on slider that triggers the slider

    • use of refs to update the width of block-1

    See demo below:

    new Vue({
      el: '#app',
      data: {
        block1W: '50%'
      },
      methods: {
        drag: function(e) {
          let dragX = e.clientX;
          let block = this.$refs.block1;
          document.onmousemove = function onMouseMove(e) {
            block.style.width = block.offsetWidth + e.clientX - dragX + "px";
            dragX = e.clientX;
          }
          // remove mouse-move listener on mouse-up
          document.onmouseup = () => document.onmousemove = document.onmouseup = null;
        }
      }
    });
    .outer {
      display: flex;
      flex-direction: row;
    }
    
    .block {
      height: 100px;
      width: 50%; /* 50% would suffice*/
    }
    
    .block-1 {
      background-color: red;
    }
    
    .block-2 {
      background-color: green;
      flex: 1; /* adjust automatically */
      min-width: 0; /* allow flexing beyond auto width */
      overflow: hidden; /* hide overflow on small width */
    }
    
    .slider {
      line-height: 100%;
      width: 10px;
      background-color: #dee2e6;
      border: none;
      cursor: col-resize;
      user-select: none; /* disable selection */
      text-align: center;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
      <div class="outer">
        <div class="block block-1" ref="block1" :style="{'width': block1W}">
          Block 1
        </div>
        <div class="slider" @mousedown="drag">
          S<br>l<br>i<br>d<br>e<br>r
        </div>
        <div class="block block-2">
          Block 2
        </div>
      </div>
    </div>

    0 讨论(0)
提交回复
热议问题