订阅并处理对多个输入的更改

Subscribe to and process change to multiple inputs

我想向输入元素添加一个事件侦听器,其中元素 ID 已存储在列表中,然后获取它们的乘积。例如:

a = ['id1', 'id2', 'id3']

我想做这样的事情:

input element id1 = 0.5
input element id2 = 0.6
input element id3 = 1.0
return 0.5*0.6*1

并且我希望它随着用户更改输入框中的值而更新。

所以我从类似的东西开始:

function calcProduct(values){
    var product = 1;
    for(i=0; values.length; i++){
        product = product*values[i];
    }
    return product
}

id_list = ['id1', 'id2', 'id3']
function calcProduct(id_list){
    for(i=0; id_list.length; i++){
        //how do I get the values as they change so I can feed it to calcProduct?
        document.getElementById(id_list[i]).addEventListener("onchange", calcProduct(values) )
    }
}
    

使用事件侦听器和 reduce() 您可以积累最终产品。注意:在事件侦听器中,省略 'on',因此使用 change 而不是 onchange。为了方便起见,我使用了一个 className 作为将要计算的输入

window.addEventListener('load', () => {
  document.querySelectorAll('.to-calc').forEach(el => el.addEventListener('change', calcProduct))
  calcProduct()
})

function calcProduct(e) {
  let output = [...document.querySelectorAll('.to-calc')].reduce((b, a) => b * +a.value, 1)
  console.log(output.toFixed(2))
  return output.toFixed(2)
}
<input class='to-calc' type='number' value='0.5'> <input class='to-calc' type='number' value='0.6'> <input class='to-calc' type='number' value='0.1'>

我会为此结合事件委托和反应式编程。

将事件侦听器附加到父节点并在事件传入时对其进行过滤:

  1. 当调度 input 事件时,父 <div> 会捕获它。
  2. filter 运算符确保我们使用正确的事件。
  3. scan 运算符将新值写入地图。
  4. map 运算符将映射中的值相乘。
  5. 最终订阅者收到并展示了产品。

这样我们就可以处理多组数字。
(请注意地图如何对应 DOM 中的 ID 和值。)

const mult = nums =>
  fromEvent(document.querySelector('div'), 'input')                       //1
  .pipe( filter(e => e.target.id in nums)                                 //2
       , scan((acc, {target: {id, value}}) => (acc[id]=value, acc), nums) //3
       , map(ns => Object.values(ns).reduce((p, n) => p * n, 1)));        //4

mult({n1: 1, n2: 1, n3: 1}).subscribe(display('#p1'));                    //5
mult({n4: 1, n5: 1, n6: 1}).subscribe(display('#p2'));                    //5
mult({n7: 1, n8: 1, n9: 1}).subscribe(display('#p3'));                    //5
input{width:30px}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.2.0/rxjs.umd.min.js" integrity="sha512-MlqMFvHwgWJ1vfts5fdC2WzxDaIXWfYuAd9Tb2lobtF61Gk+HIRDrbtxgasBSM9lZgOK9ilwK9LqFIYEV+k0IA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const {fromEvent} = rxjs;
const {filter, map, scan} = rxjs.operators;
const display = sel => val => document.querySelector(sel).textContent = val;
</script>
<div>
  <input id="n1" type="number" value="1"/> ×
  <input id="n2" type="number" value="1"/> ×
  <input id="n3" type="number" value="1"/> = <span id="p1">1</span>
  <hr/>
  <input id="n4" type="number" value="1"/> ×
  <input id="n5" type="number" value="1"/> ×
  <input id="n6" type="number" value="1"/> = <span id="p2">1</span>
  <hr/>
  <input id="n7" type="number" value="1"/> ×
  <input id="n8" type="number" value="1"/> ×
  <input id="n9" type="number" value="1"/> = <span id="p3">1</span>
</div>