代码之家  ›  专栏  ›  技术社区  ›  guettli

如果修改了表单,则切换表单的类

  •  0
  • guettli  · 技术社区  · 5 年前

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

    如果表单的一个输入被更改,我想切换表单的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

    但这会在客户端产生过多的负载。

    0 回复  |  直到 5 年前
        1
  •  2
  •   Kinglish    5 年前

    FormData快照

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

    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');
      })
    }