【问题标题】:Input range strange behavior when changing width via javascript通过javascript更改宽度时输入范围的奇怪行为
【发布时间】:2019-07-21 02:42:12
【问题描述】:

我有一组滑块,它们都可以取 0 到 100 之间的值。我需要组的总数始终小于 100,因为它们是百分比。我使用 max 属性和一些简单的数学来防止总数超过这个值。 最初我只是更改了最大值,但是,这并没有改变滑块的长度,只是一直向右的值。这会让用户感到困惑,因为 50% 的栏可能在过去位于中间时一直是正确的。

为了解决这个问题,我使用了一个容器 div,并将滑块的宽度更改为包含 div 的相应百分比。

这按预期工作,但每当您更改同级滑块时,滑块手柄会稍微移动。

有没有办法防止这些小动作。

有没有一种完全不同的更简单的方法来完成这个看似简单的任务,只使用纯 js。

    <form id="form">
        <input id="incm" type="number" value="1000"/>
        <ul>
            <li>Slider 0
                <div class="sliderContainer"><input class="slider" id="pct0" type="range" min="0" max="100" value = "50"/></div>
                <output id="pctOutput0"></output>
                <output id="amtOutput0"></output>
                </li>

            <li>Slider 1
                    <div class="sliderContainer"><input class="slider" id="pct1" type="range" min="0" max="100" value = "50"/></div>
                    <output id="pctOutput1"></output>
                    <output id="amtOutput1"></output>
                    </li>

            <li>Slider 2
                    <div class="sliderContainer"><input class="slider" id="pct2" type="range" min="0" max="100" value = "0"/></div>
                    <output id="pctOutput2"></output>
                    <output id="amtOutput2"></output>
                    </li>

            <li>Slider 3
                    <div class="sliderContainer"><input class="slider" id="pct3" type="range" min="0" max="100" value = "0"/></div>
                    <output id="pctOutput3"></output>
                    <output id="amtOutput3"></output>
                    </li>

            <li>Slider 4
                    <div class="sliderContainer"><input class="slider" id="pct4" type="range" min="0" max="100" value = "0"/></div>
                    <output id="pctOutput4"></output>
                    <output id="amtOutput4"></output>
                    </li>
            </ul>


            <p><output id="pctSum"></output><output id="amtSum"></output></p>
        </form>
function calc() {

  var pct = [],
      pctI = [],
      amt = [],
      incm = document.getElementById("incm").value

  for (i = 0; i < 5; i++) {
    pct[i] = document.getElementById("pct" + i).value
    document.getElementById("pctOutput" + i).innerHTML = pct[i] + "%"
    pctI[i] = parseInt(pct[i])

    amt[i] = pctI[i] * 0.01 * incm
    document.getElementById("amtOutput" + i).innerHTML = "£" + amt[i]
  }

  var pctSum = pctI.reduce((a,b) => a + b, 0)
  var amtSum = amt.reduce((a,b) => a + b, 0)

  document.getElementById("pctSum").innerHTML = "Total Percentage " + pctSum + "%"
  document.getElementById("amtSum").innerHTML = "Total Amount £" + amtSum

  for (i = 0; i < 5; i++) {
    document.getElementById("pct" + i).max = 100 - pctSum + pctI[i]

    document.getElementById("pct" + i).style.width = document.getElementById("pct" + i).max + "%"
  }
}

document.getElementById("form").addEventListener("input", calc)
window.onload = calc()

JSFiddle https://jsfiddle.net/Zbedjajohnson/ca5b1psy/5/

【问题讨论】:

    标签: javascript html input range


    【解决方案1】:

    非常有趣的问题。这是我想出的。

    function initSliderGroups() {
      const sliderGroups = document.querySelectorAll(".sliderGroup");
    
      for (let sliderGroup of sliderGroups) {
        const sliders = [...sliderGroup.querySelectorAll(".slider")];
        const max = sliderGroup.getAttribute('max');
        sliders.forEach(slider => {
          slider.max = max;
          slider.min = 0;
    
          const sliderContainer = document.createElement('span');
          sliderContainer.style = 'position: relative;';
          slider.parentNode.insertBefore(sliderContainer, slider);
          sliderContainer.appendChild(slider);
    
          const limitDiv = document.createElement('div');
          limitDiv.className = 'limitDiv';
          limitDiv.style = 'position: absolute; top: 4px; left: 0; z-index: 1; width: 0; height: 5px; background-color: #555; border-radius: 5px;';
          sliderContainer.appendChild(limitDiv);
    
          slider.addEventListener("input", () => onSliderInput(slider));
        });
        
        function onSliderInput(movingSlider) {
          //limit sum of values to max (defined as 100 by .sliderGroup div attribute)
          const usedByOthers = sliders.filter(s => s !== movingSlider).map(s => +s.value).reduce((a, b) => a + b);
          const available = max - usedByOthers;
          if (movingSlider.value > available) movingSlider.value = available;
    
          //update limit bars
          for (let slider of sliders) {
            const limitDiv = slider.parentNode.querySelector('.limitDiv');
    
            const usedByOthers = sliders.filter(s => s !== slider).map(s => +s.value).reduce((a, b) => a + b);
            const available = max - usedByOthers;
    
            const sliderWidth = slider.clientWidth + 1;
            const leftOffset = sliderWidth * (available / max);
            const width = sliderWidth - leftOffset;
            const extraOffset = 17 * (max - available) / max;
            limitDiv.style.left = Math.min(leftOffset + extraOffset, sliderWidth) + 'px';
            limitDiv.style.width = Math.max(width - extraOffset, 0) + 'px';
          }
        }
        
        //init
        if (sliders[0]) onSliderInput(sliders[0]);
      }
    }
    
    initSliderGroups();
    <div class="sliderGroup" max="100">
      <input class="slider" type="range" value="25" /><br/>
      <input class="slider" type="range" value="0" /><br/>
      <input class="slider" type="range" value="0" /><br/>
      <input class="slider" type="range" value="0" /><br/>
    </div>

    基本上,您只需提供所有滑块输入 class="slider",将它们包装在带有 class="sliderGroup" max="100" 的元素中,然后调用 initSliderGroups(),它会将这些滑块的最大组合值限制为 100(并显示深灰色限制条)。

    在您的情况下,您将执行以下操作:

    • class="sliderGroup" max="100" 添加到您的&lt;ul&gt;
    • 在您的 javascript 上方添加我的 javascript。
    • 删除 calc 中的 for 循环,这会更改滑块的 maxwidth

    【讨论】:

    • 我认为这将是我接受的解决方案。然而,在阅读了一些关于 JS 的文档之后,我的 JS 初学者知识有点难以理解; for let of 循环、rest 参数和箭头函数更有意义。该代码与我当前的项目很好地集成在一起,并允许我仅使用 css 调整滑块的大小。谢谢:)
    • 嘿,@ZBedjaJohnson。很高兴听到您喜欢我的解决方案,并且您不厌其烦地阅读了该解决方案,尽管它需要学习一些关于 JS 的新知识。我正在玩它,我发现我的解决方案出现了一个视觉问题,该问题出现在其他浏览器中(除了 chrome)。如果我有时间,我会在今天晚些时候尝试解决这个问题。你知道你需要支持哪些浏览器吗?
    • 浏览器支持对于这个项目来说并不是一个真正的问题,因为它只会被我使用,很高兴看到问题是什么,所以我可以在未来的公共项目中阻止它兼容会是一个问题。
    • 在 Firefox 中尝试一下,您会看到滑块上的灰色限制条没有正确对齐(它向下偏移了几个像素,向左偏移了几个像素)。看起来很糟糕,但仍然功能齐全。在 safari 中,限制栏根本不显示,但仍然功能齐全。
    • 出于某种原因,我在 chrome 上看到了该偏移量。我添加了一些临时 CSS 似乎可以解决这些问题。适用于 chrome、firefox 和 edge(需要重置拇指滑块)。如果您愿意,我可以将您链接到我的网站。
    猜你喜欢
    • 2020-08-17
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    • 1970-01-01
    相关资源
    最近更新 更多