JSFiddle - React, Tailwind, and code Playground

by niuuin

HTML

<main>
  <form id="user-form">
    <h2>添加用户</h2>
    <input type="number" name="index" hidden>
    <input type="text" name="username" placeholder="用户名">
    <input type="text" name="email" placeholder="邮箱">
    <input type="number" name="balance" placeholder="余额">
    <button type="submit">提交</button>
  </form>

  <table id="user-table">
    <thead>
    <th>用户名</th>
    <th>邮箱</th>
    <th>余额</th>
    <th class="text-right">操作</th>
    </thead>
    <tbody></tbody>
  </table>
</main>

CSS

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

:root {
  font-family: sans-serif;
  font-size: 15px;
}

input, button {
  border: 1px solid;
  padding: .5em;
  font-size: inherit;
  margin-bottom: .5em;
}

form input,
form button {
  width: 100%;
}

button {
  background: #000;
  color: #fff;
}

main {
  padding: .5em;
  margin-left: auto;
  margin-right: auto;
  max-width: 40em;
}

.error-container {
  font-size: 90%;
  padding: .5em;
  background: pink;
  color: #c10;
  margin-bottom: .5em;
}

input.error {
  border: 2px solid #c10;
  outline: 0;
}

table {
  width: 100%;
  text-align: left;
  border-collapse: collapse;
}

td, th {
  padding: .5em;
  border-bottom: 1px solid rgba(0, 0, 0, .1);
}

th {
  border-width: 2px;
  border-color: #888;
}

[hidden] {
  display: none;
}

.text-right {
  text-align: right;
}

JavaScript

/*
|--------------------------------------------------------------------------
| biaoForm.js
|--------------------------------------------------------------------------
| * 快速存取数据
| * 自定义提交行为
*/

;(function () {
  'use strict';

  let form;

  // 将biaoForm暴露出去,否则别的文件访问不到
  window.biaoForm = function (selector, onSubmit) {
    form = document.querySelector(selector);

    form.addEventListener('submit', e => {
      e.preventDefault();
      onSubmit(getData());
      form.reset();
    });

    return {
      getData, // 相当于 getData: getData
      setData, // 相当于 setData: setData
    };
  };

  /**
   * 解析表单数据(取值)
   * @param {HTMLFormElement} form 选好的form元素
   * @return {Object}
   */
  function getData () {
    // 初始化纯数据,否则解析后的数据没地方存
    let data = {};
    // 取到所有输入组件,也就是所有有name属性的元素
    // 如<input name="xxx">或者<textarea name="xxx">...
    let inputs = form.querySelectorAll('[name]');

    // 循环所有的输入组件
    inputs.forEach(it => {
      // it就是每个输入组件
      // 以<input name="age" value="10">为例:
      // it.name  ==> 'age'
      // it.value ==> '10'

      // 检查组件的类型
      switch (it.type) {
        // 如果是数字,就将值转换为数字类型
        case 'number':
          data[ it.name ] = parseFloat(it.value);
          break;
        // 如果是单选框
        case 'radio':
          // 检查它当前是否打钩了,如果没打勾就跳过
          if (!it.checked)
            return;

          // 否则就存到data中
          //    ↓'age'       ↓10
          data[ it.name ] = it.value;
          break;

        // 如果是复选框,那么取到的值就应该是个数组,
        // 因为可能会选中多项
        case 'checkbox':
          // 第一次碰到复选框,就应该将data中对应的那一项初始化为空数组
          // 否则后面没法推入选中的值
          if (!Array.isArray(data[ it.name ]))
            data[ it.name ] = [];

          /*
            如果当前的复选框打钩了,就应该推入到数组中
            <input value=a checked>
            <input value=b checked> ==> ['a', 'b']
            <input value=c>
          */
          if (it.checked)
            data[ it.name ].push(it.value);
          break;
        // 如果是以下类型中的任何一项
        case 'date':
...