【问题标题】:Toggle class of form if form was modified如果表单被修改,则切换表单类别
【发布时间】:2021-06-22 20:40:15
【问题描述】:

我有一个包含多个输入字段的表单。

如果表单的其中一个输入发生了更改,我想切换表单的 css 类,以便显示“亲爱的用户,请立即提交表单”之类的文本。

可选,但会很好:如果用户再次将输入字段更改为初始值,则应再次切换回该类,以便我可以隐藏文本(通过 css)

我不需要支持 IE,只需要支持现代浏览器。

文本的 CSS 可能如下所示:

form.unchanged div.submit-text {
    display: hidden;
}

form.changed div.submit-text {
    display: block;
}

我可以这样做:

function initChangeDetection(form) {
  Array.from(form).forEach(el => el.dataset.origValue = el.value);
}
function formHasChanges(form) {
  return Array.from(form).some(el => 'origValue' in el.dataset && el.dataset.origValue !== el.value);
}

来源:https://stackoverflow.com/a/52593167/633961

但这会在客户端造成过多的负载。

【问题讨论】:

  • 在表单中添加一个change事件监听器,它可以切换unchangedchanged类。
  • StackOverflow 不是免费的编码服务。你应该try to solve the problem first。请更新您的问题以在minimal reproducible example 中显示您已经尝试过的内容。如需更多信息,请参阅How to Ask,并拨打tour :)
  • 您的表单中有哪些元素?它是可变的,或者您可以确定表单元素的类型吗?

标签: javascript css


【解决方案1】:

FormData 快照

在@Terry 的建议下,我做了两种方法,第一种我最喜欢。它通过FormData获取原始表单的快照,将其存储在JSON中,并用于在表单更改时检查数据库中的所有元素

let oform = {}
window.onload = function() {
  let form = document.querySelector('#post'), formData = new FormData(form)
  formData.forEach((value, key) => {
    oform[key] = value;
  });
  document.querySelector('form').addEventListener('change', event => {
    let changed = Object.entries(oform).filter(el => el[1] !== document.querySelector('[name=' + [el[0]] + ']').value).length > 0,
      f = event.target.closest('form')
    if (changed) f.classList.add('changed');
    else f.classList.remove('changed');
  })
}
form{
padding:10px;
border:1px dashed #ccc;
border-radius:8px;
}

form.changed {
  background: #f0f0f0;
border:1px solid #f00;
}
label{
margin:5px 0 2px 0;
display:block
}
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600' rel='stylesheet' type='text/css'>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet">

<div class="main-block">
  <form action="/" id='post'>
    <div><label>Email*</label><input type="text" name="email" value="john@doe.com" required></div>
    <div><label>Password*</label><input type="password" value="123456" name="password" required></div>
    <label>Greetings</label>
    <select name='stuff'>
      <option></option>
      <option value='hello' selected>hello</option>
    </select>
    <button type="submit" href="/">Submit</button>
  </form>
</div>

数据属性

这种方式在页面加载时循环遍历元素并将其原始值存储在数据属性中。然后每次触发 form.change 时,循环遍历元素以测试它们的值是否与原始值匹配。这是不完善的,仅涵盖选择、文本/电子邮件/数字/时间/日期输入、复选框和单选按钮

window.onload = function() {
  document.querySelectorAll('input, select').forEach(e => {
    if (['checkbox', 'radio'].includes(e.getAttribute('type').toLowerCase())) {
      if (e.getAttribute('checked')) e.setAttribute('data-orig', 'checked');
    } else e.setAttribute('data-orig', e.value);
  })

  document.querySelector('form').addEventListener('change', (event => {
      let changed = false
      event.target.querySelectorAll('input, select').forEach(e =>
        if (['checkbox', 'radio'].includes(e.target.getAttribute('type').toLowerCase()) && e.target.getAttribute('checked') && !e.target.dataset.orig) changed = true
        else if (e.target.value !== e.target.dataset.orig) changed = true;
      });
      if (changed) event.target.classList.add('changed');
      else event.target.classList.remove('changed');
  })
}

【讨论】:

  • 与其遍历所有可能的输入元素,不如简单地将表单数据序列化为 JSON,存储/缓存它,然后在触发 input 事件时进行比较?
  • @terry - 感谢您的建议。我将其添加到我的答案中。
猜你喜欢
  • 1970-01-01
  • 2016-12-20
  • 2014-07-04
  • 2021-06-18
  • 1970-01-01
  • 1970-01-01
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多