Дорога дизайна формы формы компонента

React.js
Дорога дизайна формы формы компонента

Форма внешнего интерфейса в основном используется для решения трех типов задач: сбор данных, проверка данных и назначение данных. Решения, представленные в этой статье, могут быть прекрасно использованы на платформе React, но считается, что идея решения проблемы применима к любому языку среды.

Компоненты формы в середине и на заднем плане имеют не только ввод и выбор, но также могут быть расширены до селекторов диапазона, селекторов даты и т. д. Эти компоненты часто выполняют многоуровневую инкапсуляцию нативных компонентов для достижения более элегантного пользовательского интерфейса и многого другого. удобное взаимодействие. , а после многослойного наложения тень нативного элемента формы может перестать быть видна. Например, после инкапсуляции следующей DOM-структуры она также может стать компонентом ввода после изменения стиля, хотя тень ввода совершенно невидима.

<span>
  <span contentEditable></span>
</span>

Итак, чтобы всем было легче понять, я начну с традиционной нативной формы, чтобы у всех был прогрессивный процесс.

Введение: родная форма формы

Исходный код выглядит следующим образом:Код очень простой и выглядит очень удобно.

<form action="/api/post" method="post">
  username: <input name="username" />
  passowrd: <input name="password" />
  <button type="submit">submit</button>
</form>

Но когда вы начинаете делать валидацию данных, форма сразу усложняется. А именно: Код дублируется.

<script>
  function checkname(target) {
    const value = target.value;
    if (value.length < 10) {
      document.getElementById('username_msg').innerHTML = '长度必须>10'
    } else {
      document.getElementById('username_msg').innerHTML = ''
    }
  }
  function checkpassword(target) {
    const value = target.value;
    if (!value.match(/^[\w]{6,16}$/)) {
      document.getElementById('password_msg').innerHTML = '密码必须 6-16 位字母数字'
    } else {
      document.getElementById('password_msg').innerHTML = ''
    }
  }
  function getInitData() {
    ajax({
      url:'/api/data', 
      success:function(data) {
        document.getElementById('username') = data.username;
    });
  }
  getInitData();
</script>

<form action="/api/post" method="post">
 username: <input name="username" onchange="checkname(this)"/>
           <span id="username_msg"></span>
 passowrd: <input name="password" onchange="checkpassword(this)"/>
           <span id="password_msg"></span>
 <button type="submit">submit</button>
</form>

Если часть DOM также реализована с помощью JS, в принципе можно изменить только JS без изменения структуры DOM, но это также значительно увеличивает сложность JS.

Все структуры DOM в React генерируются сами по себе через JS, и JSX также может легко реализовать структуры DOM. Но здесь я беру в качестве примера нативную форму, просто хочу сказать, что нативная форма, написанная на React, ненамного элегантнее, чем нативная js! ! !

Нативные формы в React

Тот самый кусок простейшей функции, которая выглядит так под фреймворком реакции.

class Demo extends React.Component {
  render() {
    return <form action="/api/post" method="post">
      username: <input name="username" />
      passowrd: <input name="password" />
      <button type="submit">submit</button>
    </form>
  }
}

Например, также хотите реализовать ввод автоматической проверкиприсвоение контрольной суммы, посмотрите на следующий код, подумайте над этим много чего нужно сделать.

class Demo extends React.Component {
  state = {
    username: '',
    password: '',
    usernameMsg: '',
    passwordMsg: '',
  };
  checkname = e => {
    // 获取数据
    const value = e.target.value;
    // 受控模式赋值
    this.setState({
      username: value,
    });
    // 校验数据
    if (value.length < 10) {
      this.setState({
        usernameMsg: '长度必须>10',
      });
    } else {
      this.setState({
        usernameMsg: '',
      });
    }
  };
  checkpassword = e => {
    // 获取数据
    const value = e.target.value;
    // 受控模式赋值
    this.setState({
      password: value,
    });
    // 校验数据
    if (!value.match(/^[\w]{6,16}$/)) {
      this.setState({
        passwordMsg: '密码必须 6-16 位字母数字',
      });
    } else {
      this.setState({
        passwordMsg: '',
      });
    }
  };
  handleSubmit = () => {
    ajax({
      url: '/api/post',
      data: {
        username: this.state.username,
        password: this.state.password,
      },
      success: () => { 
        // success
      },
    });
  };
  render() {
    // 获取数据和错误信息
    const { username, password, usernameMsg, passwordMsg } = this.state;
    return (
      <form action="/api/post" method="post">
        username: <input value={username} onChange={this.checkname} />
        <span>{usernameMsg}</span>
        passowrd: <input value={password} onChange={this.checkpassword} />
        <span>{passwordMsg}</span>
        <button type="submit" onClick={this.handleSubmit}>
          submit
        </button>
      </form>
    );
  }
}

Код немного длинный, но в основном явление можно заключить.Чтобы добиться сбора и проверки данных формы, он в основном неразделим.onChangeЭтот метод, и есть несколько элементов управления формы, необходимо написать несколько onChange. (Приведенный выше код можно запустить напрямую, и его можно найти вкодовый спрей.IO/Frank front/fear...отладка)

На самом деле это никак не связано с фреймворком, потому что какой бы фреймворк для этого не использовалсяназначатьа такжечек об оплатеЭти две функции в основном должны быть привязаны к onChange на входе. Итак, если есть общий инструмент, который может автоматически выполнять все привязки onChange за вас, а затем исправлять правила проверки, можно ли решить все проблемы с формами? Да, решение Universal Forms было разработано с учетом этого!

Решение для всех компонентов формы React

Все компоненты, написанные на React, могут использовать эту схему. Даже системы, не относящиеся к React, могут использовать идею для решения проблем.

Основываясь на том принципе, что все элементы управления формы должны быть связаны с изменением для получения и проверки данных, я разработалFieldинструмент. Принцип этого инструмента очень прост, то есть он может автоматически помочь вам связать значение + onChange, чтобы решить проблему длинного списка кодов выше.

const field = new Field(this);

field.init('username');

field.init автоматически вернет значение + onChange со следующим содержимым:

{
  value: "",
  onChange: ƒ ()
}

На следующем рисунке кратко показаны отношения между Field и системой React.


Получить данные с помощью поля

import {Field} from '@alifd/next';

class Demo extends React.Component {
  field = new Field(this);
  handleSubmit = () => {
    console.log(this.field.getValues()); // 获取数据
  }
  render() {
    const {init} = this.field;
    return <form>
      username: <input {...init('username')} />
      passowrd: <input {...init('password')} />
      <button onClick={this.handleSubmit} >submit</button>
    </form>
  }
}

Проблема получения данных такой формы решена, а код намного проще. Демо здеськодовый спрей.IO/Frank front/fear...Вы можете отладить его самостоятельно

проверка формы

Теперь, когда данные могут быть получены, проверка формы становится гладкой, потому что проверка зависит только от данных. Нам просто нужно абстрагироваться от централизованной фиксированной формы интерактивности и правил проверки.

Форма взаимодействия примерно включает следующие три категории

  • Проверка в реальном времени при вводе, как правило, срабатывает onChange
  • Проверяйте при выходе из фокуса, вообще onBlur срабатывает
  • Запустите проверку с помощью пользовательской операции и вызовите API, чтобы запустить ее самостоятельно.

Абстракции общих правил проверки

имя правила

описывать

Типы

Условия срабатывания/тип данных

required Не может быть пустым Boolean undefined/null/“”/[]
pattern Проверить регулярное выражение Обычный
minLength Минимальная длина строки/минимальное количество массивов Number String/Number/Array
maxLength Максимальная длина строки/максимальное количество массивов Number String/Number/Array
length Точная длина строки / точное число массива Number String/Number/Array
min минимум Number String/Number
max максимальное значение Number String/Number
format

Краткое изложение общих шаблонов

url/email/tel/number

String String
validator таможенный чек Function

Это показывает, что форма ниже представляет собой слабо типизированные данные. Например, в поле ввода вы хотите, чтобы пользователь ввел целое число, а возвращаемое значение может иметь два типа.

  • "123456", целочисленный метод проверки типа String: /\d+/
  • 123456, Целочисленный метод проверки типа Number: typeof Value === 'number'

В настоящее время очень недружелюбно требовать, чтобы пользователь возвращал числовой тип для проверки, поэтому проблема с типом решается в логике проверки поля, а не остается на усмотрение пользователя.

Вышеупомянутый небольшой эпизод, продолжим рассматривать код Поле+Форма следующим образом, который решает все функции сбора данных и проверки формы.

import { Field } from '@alifd/next';

class Demo extends React.Component {
  field = new Field(this);
  handleSubmit = (e) => {
    e.preventDefault();
    this.field.validate(); // 自定义校验
    console.log(this.field.getValues()); // 获取数据
  }
  render() {
    const {init, getError} = this.field;
    
    return <form>
      username: <input {...init('username', {rules: { required: true, minLength: 10}})} />
      <span style={{color: 'red'}}>{getError('username')}</span>  {/**错误信息**/}
      passowrd: <input {...init('password', {rules: {
          pattern: /^[\w]{6,16}$/,
          message: '密码必须 6-16 位字母数字'
        }})} />
      <span style={{color: 'red'}}>{getError('password')}</span>  {/**错误信息**/}
      <button onClick={this.handleSubmit} >validate</button>
    </form>
  }
}

Таким образом, можно решить 24 строки кода, для которых раньше требовалось 70 строк кода, что может сделать код намного понятнее. Демонстрация отладки см.:кодовый спрей.IO/Frank front/fear...


Как использовать компоненты формы, написанные самостоятельно

Многие компоненты React теперь инкапсулированы поверх нативных компонентов, и многие компоненты могут не включать в себя элементы формы (например,Fusion SelectВ нем нет элемента select, выпадающий список сделан сам). Но вы можете использовать эту схему, если ваши собственные компоненты также следуют правилам формы.

Основные правила: управляемые правила value + onChange

На самом деле это правило исходит из нативных html-компонентов.Компоненты, написанные нами, могут использовать Field, если они соответствуют стандарту.


Компоненты, написанные вами, более красивы и интерактивны, чем нативные компоненты форм. При соблюдении спецификации его можно использовать в полевых условиях, см. подробную демонстрациюкодовый спрей.IO/Frank front/fear...

Более удобные функции

Существуют и другие более подробные правила, позволяющие улучшить компоненты для расширенных функций, например:

  • Сброс в один клик для очистки всех данных. Поскольку тип полученных данных каждого компонента отличается, он унифицирован для получения значения = undefined в willReceiveProps.
componentWillReceiveProps(nextProps) {
    if ('value' in nextProps ) {
        this.setState({
           value: nextProps.value === undefined? []: nextProps.value   //  设置组件的被清空后的数值
        })
    }
}
  • Выбрасывать onChange только один раз за взаимодействие
    • Например, загрузка загрузки, если одна загрузка вызывает сотни onChange, то вся страница будет рендериться сотни раз вместе с ней, что сильно влияет на производительность.


    • Например, Slider, если onChange срабатывает в реальном времени при перетаскивании, он может сильно застревать при перетаскивании ползунка. Таким образом, момент отпускания мыши является более разумной операцией, а другие события перетаскивания могут быть переданы onProgress.


Компоненты формы Fusion Next в основном реализованы в соответствии с этим набором спецификаций.Для получения дополнительной информации вы можете проверить документацию здесь.Fusion.design/component/ ...тянуть на дно

Компонент Form постоянно обновляет интерфейс.

Из вышеизложенного известно, что Field может решить проблемы с данными, такие как проверка, сбор и назначение, но не может решить проблемы пользовательского интерфейса и взаимодействия, вам нужно самостоятельно контролировать макет и отображение ошибок.

Сделать макет проще

Компоновка сцены включает в себя горизонтальную встроенную компоновку и вертикальную компоновку столбцов, что можно легко сделать с помощью API FormItem.

  • вертикальное расположение
<Form>
  <FormItem label="Username:">
    <Input name="first"  placeholder="first"/>
    <Input name="second" placeholder="second"/>
  </FormItem>
  <FormItem label="Password:" required>
    <Input htmlType="password" name="pass" placeholder="Please enter your password!"/>
  </FormItem>
  <FormItem label=" ">
    <Form.Submit>Submit</Form.Submit>
  </FormItem>
</Form>


  • Горизонтальное расположение
<Form inline>...</Form>


  • Встроенный тег
<Form labelAligin="inset">...</Form>


Вспомогательный дисплей ошибок

При возникновении ошибки автоматически отображается сообщение об ошибке, и нет необходимости судить по getError самостоятельно. То, как отображается каждое состояние, реализуется самим соответствующим компонентом. Уменьшите связь с Form


Загрузка, успех и сбой каждого компонента реализуются самим компонентом.Form только передает состояние каждому компоненту во время проверки, так что Form не нужно заботиться о том, как должен выглядеть каждый компонент!

<Input state="error" />  // 错误状态
<Input state="loading" /> // 加载中
<Input state="success" /> // 成功
<DatePicker state="error" /> // 错误状态

Дальнейшая оптимизация формы, чтобы упростить ее использование.

Выше мы по-прежнему используем Field + Form вместе, код в основном такой.

import { Form, Input, Field, Button } from '@alifd/next';

const FormItem = Form.Item;

class Demo extends React.Component {
  field = new Field(this);
  handleSubmit = () => {
    this.field.validate();
  }
  render() {
    const {init} = this.field;
    return  <Form field={this.field}>
        <FormItem label="Username:">
            <Input {...init('username', {
              rules: {required}
            })} />
        </FormItem>
        <FormItem label="Password:">
            <Input {...init('password', {
              rules: {pattern:/[\w]{6,16}/}
            })} htmlType="password" />
        </FormItem>
        <FormItem label=" ">
            <Button onClick={this.handleSubmit} >Submit</Button>
        </FormItem>
    </Form>
  }
}

Может быть, написав слишком много, вы подумаете,Каждый компонент должен использовать init и правила должны быть написаныи написать большую строку данных JSON в jsx.

Есть ли способ упростить сбор и проверку данных, чтобы еще больше упростить код?

Дальнейшая интеграция полевых возможностей и сокращение использования

В ответ на вышеуказанные проблемы форма дополнительно оптимизирована, возможности поля интегрированы в форму, а использование поля еще больше ослаблено, так что всем больше не нужно заботиться об инициализации/выборке данных и других проблемах. код показывает, как показано ниже:

import { Form, Input, Button } from '@alifd/next';

const FormItem = Form.Item;

class Demo extends React.Component {
  handleSubmit = (values, errors) => {
    if (errors) {
      // 校验出错 
      return;
    }
    console.log(values) // 获取数据
  }
  render() {
    return  <Form>
        <FormItem label="Username:" required>
            <Input name"username" />
        </FormItem>
        <FormItem label="Password:" pattern={/[\w]{6,16}/}>
            <Input name="password" htmlType="password" />
        </FormItem>
        <FormItem label=" ">
            <Form.Submit validate onClick={this.handleSubmit} >Submit</Form.Submit>
        </FormItem>
    </Form>
  }
}

В приведенном выше коде можно увидеть несколько точек оптимизации:

  1. Вам не нужно обращать внимание на использование поля и менять его на Form API. Простой и понятный в использовании
  2. Инициализация данных через имя также ближе к использованию нативной формы, которую легче понять каждому.
  3. Функция проверки основана на API, код стал более лаконичным, а читабельность улучшена.

постскриптум

Оптимизация формы не должна останавливаться на достигнутом, потому что в реальном бизнесе будут встречаться более сложные функции.

Чтобы быть более удобным и быстрым, многие предприятия будут абстрагироваться от общего макета компонентов и напрямую отображать форму динамически на внешнем интерфейсе, выплевывая схему JSON через внутренний интерфейс.Хотя это действительно удобно и быстро, когда это более ориентированный на бизнес, он может значительно решить проблему эффективности;

Или превратите общие сценарии классов форм в бизнес-компоненты и шаблоны модулей, а затем загрузите и используйте их непосредственно при их использовании. Например: модуль класса формы Fusion:fusion.design/module?Протрите...

Вариантов много, и всегда найдется тот, который подходит именно вам.

Ссылки по теме