如何解决输入连续性匹配

时间:2019-01-13 02:20:02

标签: javascript html html5

我正在使用计算器,它需要有四个输入,每个输入的最大值为100,且四个输入的总和始终等于100。 实现良好UX的最佳方法是,在将任何滑块向上移动之前将其向下移动。如果滑块还不为零,则在滑块向下移动之后立即向上滑动。

我尝试匹配输入名称并添加公式。我真的不知道解决此问题的最佳方法。

enter image description here

5 个答案:

答案 0 :(得分:2)

<!-- Author: devninja67 -->
<!-- ***** -->
<!DOCTYPE html>
<html>
<head>
	<script type="text/javascript">
		// Returns all selector elements
		const getRanges = () => Array.from(document.querySelectorAll('.hrange'));

		// return value to change
		const minValue = (v1, v2) => {
			if(v1 < 0)  return Math.abs(v1) < v2 ? v1 : -v2;
			else return v1 < 100 - v2 ? v1 : 100 - v2;
		}

		// Gets us an ability to sum selectors (can exclude a selector if required)
		const sumSelectors = (exclude) => getRanges()
		    .filter((r) => (exclude) ? r !== exclude : true)
		    .map(r => parseInt(r.value))
		    .reduce((a, s) => a + s);
		
		// changing before or after slider
		const checkRanges = (idx) => {
		// after element for increasing and before element for decreasing
	   	let stride = (sumSelectors() > 100) ? 1 : -1;
	    let selectorId = idx;
		// changing slider's value until sliders's sum equal 100
	    while(true) {
	     	selectorId = (selectorId + stride + 4) % 4;
	     	let selector = document.querySelector("#range" + selectorId);
	    	let selectorValue = parseInt(selector.value);
	    	selector.value = selectorValue + minValue(100 - sumSelectors(), selectorValue);
	    	if(sumSelectors() !== 100) continue;
	    	else break;
			}
		  document.querySelector('#amount').value = sumSelectors();
		};

		// Listening inputing slider
		document.addEventListener('DOMContentLoaded', function() {
		  getRanges().forEach((r, idx) => {
		    r.addEventListener('input', (event) => {
		      checkRanges(idx);
		    });
		  });
		});
	</script>

	<style type="text/css">
		.hrange {
  		display: block;
		}
	</style>
</head>
<body>
	<div class="hThree">
	  <input type="range" id="range0" orient="vertical" value="25" class="hrange" min="0" max="100" />
	  <input type="range" id="range1" orient="vertical" value="25" class="hrange" min="0" max="100" />
	  <input type="range" id="range2" orient="vertical" value="25" class="hrange" min="0" max="100" />
	  <input type="range" id="range3" orient="vertical" value="25" class="hrange" min="0" max="100" />
	  <input id="amount" type="number" value="100" min="0" max="100" />
	</div>
</body>
</html>

答案 1 :(得分:1)

我认为这对您有用。 让我知道。

一些注意事项:

  • 已删除ID属性,因为HTML中不允许重复
  • 删除了BR标签,并使用了CSS(更好)。
  • 如果您超过100,则循环会将循环模型中的下一个最高值减少1,直到您等于或小于100。
  • 经过调整,现在始终为100。
  • 对代码进行了大量的整理。

// Returns all selector elements
const getRanges = () => Array.from(document.querySelectorAll('.hrange'));

// Gets us an ability to sum selectors (can exclude a selector if required)
const sumSelectors = (exclude) => getRanges()
    .filter((r) => (exclude) ? r !== exclude : true)
    .map(r => parseInt(r.value))
    .reduce((a, s) => a + s);

// Get the selector with highest current value.
const maxSelector = (exclude) => getRanges()
    .filter(r => (exclude) ? exclude !== r : true)
    .reduce((a, r) => (parseInt(r.value) > parseInt(a.value)) ? r : a);;

const minSelector = (exclude) => getRanges()
    .filter(r => (exclude) ? exclude !== r : true)
    .reduce((a, r) => (parseInt(r.value) < parseInt(a.value)) ? r : a);
;

const checkRanges = (r) => {
  while (sumSelectors() !== 100) {
    let stride = (sumSelectors() > 100) ? -1 : 1;
    let selector = (stride === -1) ? maxSelector(r) : minSelector(r);
    selector.value = parseInt(selector.value) + stride;
  }
  document.querySelector('#amount').value = sumSelectors();
};


document.addEventListener('DOMContentLoaded', function() {
  getRanges().forEach(r => {
    r.addEventListener('change', (event) => {
      checkRanges(r);
    });
  });
  
  checkRanges();
});
.hrange {
  display: block;
}
<div class="hThree">
  <input type="range" orient="vertical" value="0" class="hrange" min="0" max="100" />
  <input type="range" orient="vertical" value="0" class="hrange" min="0" max="100" />
  <input type="range" orient="vertical" value="0" class="hrange" min="0" max="100" />
  <input type="range" orient="vertical" value="0" class="hrange" min="0" max="100" />
  <input id="amount" type="number" value="100" min="0" max="100" />
</div>

答案 2 :(得分:0)

const getRanges = () => Array.from(document.querySelectorAll('.hrange'));

const minValue = (v1, v2) => {
  if(v1 < 0)  return Math.abs(v1) < v2 ? v1 : -v2;
  else return v1 < 100 - v2 ? v1 : 100 - v2;
}

const sumSelectors = (exclude) => getRanges()
    .filter((r) => (exclude) ? r !== exclude : true)
    .map(r => parseInt(r.value))
    .reduce((a, s) => a + s);

const objSelector = (selectorId) => {
    let result
    getRanges().forEach((object, index) => {
      if(index === selectorId) result = object
    })
    return result
  }

const checkRanges = (changed_obj, changed_idx) => {
  let stride = (sumSelectors() > 100) ? 1 : -1;
  let selectorId = changed_idx;
  while(true) {
    selectorId = (selectorId + stride + 4) % 4;
    let selector = objSelector(selectorId)
    let selectorValue = parseInt(selector.value);
    selector.value = selectorValue + minValue(100 - sumSelectors(), selectorValue);
    if(sumSelectors() !== 100) continue;
    else break;
  }
  document.querySelector('#amount').value = sumSelectors();
};

document.addEventListener('DOMContentLoaded', function() {
  getRanges().forEach((object, index) => {
    object.addEventListener('input', (event) => {
      event.target.value = (event.target.value < 0 ? 0 : (event.target.value > 100 ? 100: event.target.value));
      checkRanges(object, index);
    });
  });
});
.hrange {
  display: block;
}
<div class="hThree">
  <input type="range" orient="vertical" value="100" class="hrange" min="0" max="100" />
  <input type="range" orient="vertical" value="0" class="hrange" min="0" max="100" />
  <input type="range" orient="vertical" value="0" class="hrange" min="0" max="100" />
  <input type="range" orient="vertical" value="0" class="hrange" min="0" max="100" />
  <input id="amount" type="number" value="100" min="0" max="100" />
</div>

答案 3 :(得分:0)

<!DOCTYPE html>
<html>
<head>
  <title>Sliders</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
</head>

<body>
  <div id="Sliders">
    <div>
  <input type="range" id="0" name="1"
         min="0" max="100" v-model.number="countity_sliders[0]" step="1" @input="reorder">
  <label for="volume">First: {{ countity_sliders[0] }}</label>
</div>

<div>
  <input type="range" id="1" name="2"
         min="0" max="100" v-model.number="countity_sliders[1]" step="1" @input="reorder">
  <label for="volume">Second: {{ countity_sliders[1] }}</label>
</div>
<div>
  <input type="range" id="2" name="3"
         min="0" max="100" v-model.number="countity_sliders[2]" step="1" @input="reorder">
  <label for="volume">Third: {{ countity_sliders[2] }}</label>
</div>
<div>
  <input type="range" id="3" name="4"
         min="0" max="100" v-model.number="countity_sliders[3]" step="1" @input="reorder">
  <label for="volume">Fourth: {{ countity_sliders[3] }}</label>
</div>
<div>
  <hr>
  summ: {{ summa }} <br>
</div>
  </div>

  <script>
    var app = new Vue({
      el: '#Sliders',
      data: {
        countity_sliders: [100,0,0,0],
        sliders_order: [0,1,2,3],
        summa: 0
      },
      methods: {
        reorder($element) {
          this.sliders_order=[parseInt($element.target.id)].concat(this.sliders_order);
          this.sliders_order = Array.from(new Set(this.sliders_order));
          this.check_summ_rule()

        },
        check_summ_rule() {
          this.summa = (this.countity_sliders[0] + this.countity_sliders[1]+ this.countity_sliders[2] + this.countity_sliders[3])
          if (this.summa > 100) {
            if (this.countity_sliders[this.sliders_order[1]]>0) {
              this.countity_sliders[this.sliders_order[1]] = this.countity_sliders[this.sliders_order[1]]-(this.summa -100);
            } else if (this.countity_sliders[this.sliders_order[2]]>0) {
              this.countity_sliders[this.sliders_order[2]] = this.countity_sliders[this.sliders_order[2]]-(this.summa -100);
            } else if (this.countity_sliders[this.sliders_order[3]]>0) {
              this.countity_sliders[this.sliders_order[3]] = this.countity_sliders[this.sliders_order[3]]-(this.summa -100);
            }
          }
          this.summa = (this.countity_sliders[0] + this.countity_sliders[1]+ this.countity_sliders[2] + this.countity_sliders[3])
          if (this.summa < 100) {
            if (this.countity_sliders[this.sliders_order[1]]>-1) {
              this.countity_sliders[this.sliders_order[1]] = this.countity_sliders[this.sliders_order[1]]+(100 - this.summa);
            } else if (this.countity_sliders[this.sliders_order[2]]>-1) {
              this.countity_sliders[this.sliders_order[2]] = this.countity_sliders[this.sliders_order[2]]+(100 - this.summa);
            } else if (this.countity_sliders[this.sliders_order[3]]>-1) {
              this.countity_sliders[this.sliders_order[3]] = this.countity_sliders[this.sliders_order[3]]+(100 - this.summa);
            }
          }
          if (this.countity_sliders[0] < 0 ) this.countity_sliders[0] = 0
          if (this.countity_sliders[1] < 0 ) this.countity_sliders[1] = 0
          if (this.countity_sliders[2] < 0 ) this.countity_sliders[2] = 0
          if (this.countity_sliders[3] < 0 ) this.countity_sliders[3] = 0
          this.summa = (this.countity_sliders[0] + this.countity_sliders[1]+ this.countity_sliders[2] + this.countity_sliders[3])
          }

        }

      })
  </script>
</body>
</html>

答案 4 :(得分:0)

<!--   Author : Mehran   -->
<!DOCTYPE html>
<html>
<head>
    <title>Four Sliders</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
</head>

<body>
    <div id="FourSliders">
        <input type="range" id="0" min="0" max="100" v-model="val[0]" @input="changed" /><br/>
        <input type="range" id="1" min="0" max="100" v-model="val[1]" @input="changed" /><br/>
        <input type="range" id="2" min="0" max="100" v-model="val[2]" @input="changed" /><br/>
        <input type="range" id="3" min="0" max="100" v-model="val[3]" @input="changed" /><br/>
        Sum : <input type="number" value="100" v-model="sum" />
    </div>

    <script>
        var app = new Vue({
            el: '#FourSliders',
            data: {
                val: [100, 0, 0, 0],
                sum: 100
            },
            methods : {
                changed(e) {
                    var i;
                    var dif = Number(this.val[0]) + Number(this.val[1]) + Number(this.val[2]) + Number(this.val[3]) - Number(this.sum);
                    for (i = 0; i < 4; i++) {
                        if (i == e.target.id) continue;
                        if (dif > 0) {
                        if (this.val[i] - dif > 0) {
                            this.val[i] -= dif;
                            break;
                        }
                        else
                            dif -= this.val[i], this.val[i] = 0;
                        }
                        else {
                        if (this.val[i] - dif <= 100) {
                            this.val[i] -= dif;
                            break;
                        }
                        else
                            dif += (100-this.val[i]), this.val[i] = 100;
                        }
                    }
                }
            }
        })
    </script>
</body>
</html>