Измените пропорции ширины двух блоков с помощью ползунка

#javascript #css #vue.js #flexbox

#javascript #css #vue.js #flexbox

Вопрос:

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

codpen и демо:

 .outer {
  display: flex;
  flex-direction: row;
}

.block {
  height: 200px;
  width: -webkit-calc(50% - 5px);
  width: -moz-calc(50% - 5px);
  width: calc(50% - 5px);
}

.block-1 {
  background-color: red;
}

.block-2 {
  background-color: green;
}

.slider {
  line-height: 100%;
  width: 10px;
  background-color: #dee2e6;
  border: none;
  cursor: e-resize;
}  
 <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>  

Я попытался использовать draggable-vue-directive и изменить ширину блоков в зависимости от положения ползунка.

Однако это сработало не очень хорошо, так как draggable-vue-directive установите ползунок на position:fixed , что, в свою очередь, испортило выравнивание блоков.

Как я могу сделать .slider блок горизонтально перетаскиваемым без настройки position:fixed ?

Как правильно изменять размер Block1 и Block2 при перемещении ползунка?

Примечание: я не использую jQuery

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

1. Существует множество способов создания ползунка. Чего вы пытаетесь достичь с его помощью? Ваша текущая реализация просто изменит содержимое в каждой области по мере их расширения / сужения. Это цель?

2. @BryceHowitson да, в принципе, если вы сдвинете ползунок div вправо, то он Block 1 должен быть шире, а Block 2 — уже

Ответ №1:

Вы можете настроить свой flexbox вместе с resize недостатком является то, что ползунок не очень настраивается:

  • добавить resize: horizontal к одному из элементов flex
  • добавить flex: 1 к другому гибкому элементу (чтобы этот гибкий элемент автоматически корректировался в ответ на изменение ширины другого гибкого элемента по мере его изменения)

Смотрите демонстрацию ниже:

 .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>  


Поэтому мы будем использовать vanilla JS вместо решения resize, описанного выше:

  • используйте mousedown прослушиватель, который регистрирует mousemove прослушиватель, который обновляет block-1 ширину (и сбрасывает mouseup событие)
  • также подумайте о том, min-width: 0 чтобы переопределить min-width: auto block-2 элемент

Смотрите демонстрацию ниже:

 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>  


Решение

Вы можете легко адаптировать вышеуказанное в Vue, не используя для этого какие-либо пользовательские плагины Vue — изменения:

  • @mousedown прослушиватель, slider который запускает ползунок

  • использование refs для обновления ширины block-1

Смотрите демонстрацию ниже:

 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>  

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

1. Действительно отличный ответ. Также довольно приятно, что решение сначала основано на «ванильном» JS, а затем «перенесено» в решение, ориентированное на Vue. Лично я бы просто использовал addEventListener вместо использования свойств «вкл. …» в JS, но здесь это не важно для общей функциональности. Хорошая работа. Большое вам спасибо.