为什么在输入中添加小数点会清除输入?

Bas*_*asj 13 javascript html-input

我正在用 Javascript 做一个小数字键盘,但我无法通过.以下方式添加小数点:<input type="number">

document.getElementById('2').onclick = () => document.getElementById('input').value += '2';
document.getElementById('.').onclick = () => document.getElementById('input').value += '.';
Run Code Online (Sandbox Code Playgroud)
<input id="input" type="number" value="3"></input>
<div id="2">click to add 2</div>
<div id=".">click to add .</div>
Run Code Online (Sandbox Code Playgroud)

指定值“3”。无法解析,或者超出范围。

但另一方面,当输入有焦点时,我们可以用键盘手动输入小数点。

完整示例:

var target = document.querySelector('#input');
document.querySelectorAll('.calcbutton').forEach(el => el.addEventListener("click", evt => { target.value += evt.target.innerHTML; }));
document.querySelector('.calcpoint').onclick = evt => { if (!target.value.includes('.')) target.value += '.'; };
Run Code Online (Sandbox Code Playgroud)
<input id="input" type="number"></input>
<div id="calc">
<table>
<tr><td class="calcbutton">7</td><td class="calcbutton">8</td><td class="calcbutton">9</td></tr>    
<tr><td class="calcbutton">4</td><td class="calcbutton">5</td><td class="calcbutton">6</td></tr>    
<tr><td class="calcbutton">1</td><td class="calcbutton">2</td><td class="calcbutton">3</td></tr>
<tr><td class="calcbutton">0</td><td class="calcpoint">.</td><td class="calcenter">ENTER</td></tr>    
</table>
</div>
Run Code Online (Sandbox Code Playgroud)

为什么按会.清除输入?

Fel*_*lix 11

如果设置了一个值(每个 JS),它的工作方式如下(从规范复制)

  1. 令 oldValue 为元素的值。
  2. 将元素的值设置为新值。
  3. 将元素的脏值标志设置为 true。
  4. 如果元素的 type 属性的当前状态定义为 1,则调用值清理算法。
  5. 如果元素的值(应用值清理算法后)与 oldValue 不同,并且该元素具有文本输入光标位置,则将文本输入光标位置移动到文本控件的末尾,取消选择任何选定的文本并重置选择方向到“无”。

这意味着它会立即检查它是否适合数字的模式,而在用户输入时,它会等待稍后的时间点(基本上是为了允许添加小数点)

有关更多信息,请参阅https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value 。


Koo*_*Inc 5

我想这是因为输入字段的数字类型及其卫生(由解释器,请参阅@Felix'答案)。

如果您想继续使用数字字段,解决此问题的一个想法可能是使用隐藏文本字段来填充数字字段(使用parseFloat)。这是一个片段(演示中未隐藏文本字段),使用事件委托进行处理。

document.addEventListener(`click`, handle);

function handle(evt) {
  if (evt.target.matches(`.calcbutton`)) {
    const value = evt.target.textContent;
    const inpNr = document.querySelector('#input');
    const inpTxt = document.querySelector('#inputTxt');
    const hasDot = /\./.test(inpTxt.value);
    // only one dot allowed
    inpTxt.value += hasDot && value === `.` ? `` : value;
    return inpNr.value = parseFloat(inpTxt.value);
  }
  
  // for demo: hide text or number field to see what it's like
  if (evt.target.matches(`[data-hidden]`)) {
    if (evt.target.dataset.hidden === `txt`) {
      document.querySelector('#input').closest(`div`).style.display = `none`;
      document.querySelector('#inputTxt').closest(`div`).style.display = ``;
      evt.target.dataset.hidden = `nr`;
      return evt.target.textContent = `Hide text field`;
    }
    
    document.querySelector('#input').closest(`div`).style.display = ``;
    document.querySelector('#inputTxt').closest(`div`).style.display = `none`;
    evt.target.dataset.hidden = `txt`;
    return evt.target.textContent = `Hide number field`;
  }
}
Run Code Online (Sandbox Code Playgroud)
.calcbutton {
  cursor: pointer;
  font-size: 1.5rem;
  font-weight: bold;
}
Run Code Online (Sandbox Code Playgroud)
<div><input id="input" type="number" readonly> Number</div>
<div style="display:none"><input id="inputTxt" type="text" readonly> Text</div>
<div id="calc">
  <table>
    <tr>
      <td class="calcbutton">7</td>
      <td class="calcbutton">8</td>
      <td class="calcbutton">9</td>
    </tr>
    <tr>
      <td class="calcbutton">4</td>
      <td class="calcbutton">5</td>
      <td class="calcbutton">6</td>
    </tr>
    <tr>
      <td class="calcbutton">1</td>
      <td class="calcbutton">2</td>
      <td class="calcbutton">3</td>
    </tr>
    <tr>
      <td class="calcbutton">0</td>
      <td class="calcbutton">.</td>
      <td class="calcenter">ENTER</td>
    </tr>
  </table>
</div>
<button data-hidden="txt">Hide number field</button>
Run Code Online (Sandbox Code Playgroud)