使用滑块更改两个块的宽度比例

Posted

技术标签:

【中文标题】使用滑块更改两个块的宽度比例【英文标题】:Change width proportions of two blocks with a slider 【发布时间】:2019-08-28 18:46:36 【问题描述】:

我正在尝试设计一个组件,您可以在其中通过左右移动滑块来更改两个块的宽度比例:

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,这反过来又搞乱了块对齐。

如何在不设置position:fixed 的情况下使.slider 块水平拖动?

当滑块移动时如何正确调整Block1Block2 的大小?

注意:我没有使用jQuery

【问题讨论】:

制作滑块的方法有很多。你想用它来完成什么?您当前的实现将简单地重排每个区域中的内容,因为它们变得更宽/更窄。这是目标吗? @BryceHowitson 是的,基本上如果您将滑块 div 向右滑动,那么 Block 1 应该更宽,Block 2 应该更窄 【参考方案1】:

你可以调整你的 flexboxresize - 缺点slider 它不是非常可定制:

resize: horizontal 添加到弹性项目之一 将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: autoblock-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 插件 - 更改如下:

@mousedownslider 上的侦听器 触发滑块

使用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>

【讨论】:

确实很好的答案。该解决方案首先基于“vanilla” JS,然后“迁移”到以 Vue 为目标的解决方案,这也很不错。就个人而言,我只会使用 addEventListener 而不是在 JS 中使用“on...”属性,但这对于一般功能来说并不重要。干得好。非常感谢。

以上是关于使用滑块更改两个块的宽度比例的主要内容,如果未能解决你的问题,请参考以下文章

如何将另一个图像添加到滑块的拇指或如何添加两个拇指图像?

如何使用 jQuery 中的滑块更改样式的值

CSS - Firefox 中滑块的宽度

带有两个滑块的QSlider

带有两个滑块的交互式 matplotlib 图

“bxslider jquery”以指定的宽度更改幻灯片模式