Источник изображения:unsplash.com/
Автор этой статьи: Дун Цзяньхуа
1. Предпосылки
Бизнес-сценарии Cloud Music B-терминала, бизнес-терминал B длиннее, чем жизненный цикл бизнес-продукта C-терминала, и больше ориентирован на сцену сцены. Много раз разработка B-терминала представляла собой код перед копированием, что добавляло много повторений и утомительную рабочую нагрузку.
На самом деле промежуточные и серверные системы можно разделить на несколько общих сценариев: формы, таблицы и диаграммы.Формы включают в себя сложные сценарии, такие как связывание, проверка и макет, на решение которых разработчикам часто приходится тратить энергию.
по сравнению с традиционнымAnt DesignМетод разработки формы развития, мы считаем, что существуют следующие проблемы:
- Во-первых, код нельзя сериализовать, а это более привычно некоторым не фронтенд разработчикам.
JSON
способ описать форму, потому что достаточно простой - Проверка формы не сочетается с состоянием проверки
-
onChange
Реализованный метод компоновки будет сложно поддерживать в сложных ситуациях компоновки, и легко сгенерировать много логики связанного списка. - Формы имеют много взаимоисключающих состояний для организации, и мы хотим, чтобы пользователи могли легко переключаться между этими состояниями.
- Для некоторых распространенных и распространенных сценариев, таких как списки форм, также можно извлечь набор возможных решений.
Поэтому, несмотря на то, что традиционный метод разработки формы достаточно гибок, я все же думаю, что форма все еще имеет возможности для оптимизации и сделала некоторые компромиссы между гибкостью и эффективностью.
Во внешнем мире есть и более зрелые формы, такие как:Formliy,FormRender. Несмотря на то, что некоторые из вышеперечисленных пунктов были решены, это все еще недостаточно полно.style
строить планы.
Поэтому, чтобы повысить эффективность разработки мидл- и бэкенда и позволить фронтенду посвятить время более содержательным вещам, мы обобщили набор форм-решений для сложных сценариев.
2. Технические решения
Наиболее важной частью технического решения является дизайн схемы, а архитектура фреймворка и другие работы реализуются по этой ссылке, поэтому я буду следовать этой идее, чтобы представить вам.
2.1 Дизайн схемы
Схема формы основана наAnt Design
разработаноJSON
Расположенная схема, но неJSON Schema
, многие аутсайдеры основаны наJSON Schema
Схема комплектации, собственно, тоже рассматривалась, ноJSON Schema
Немного неудобно писать, так что даJSON Schema
Преобразование доступно только как дополнительная возможность.
Случай показан в следующем коде, нужно только настроить самое простое поле формыkey
,type
а такжеui.label
Просто хорошо:
const schema = [
{
"key": "name",
"type": "Input",
"ui": {
"label": "姓名"
}
},
{
"key": "age",
"type": "InputNumber",
"ui": {
"label": "年龄"
},
"props": {
"placeholder": "请输入年龄"
}
},
{
"key": "gender",
"type": "Radio",
"value": "male",
"ui": {
"label": "性别"
},
"options": [
{
"name": "男",
"value": "male"
},
{
"name": "女",
"value": "female"
}
]
}
];
export default function () {
const formRef = useRef(null);
const onSubmit = () => {
formRef.current.submit().then((data: any) => {
console.log(data);
});
};
const onReset = () => {
formRef.current.reset();
};
return (
<>
<XForm
ref={formRef}
schema={schema}
labelCol={{ span: 6 }}
wrapperCol={{ span: 12 }}
/>
<div>
<Button type="primary" onClick={onSubmit}>提交</Button>
<Button onClick={onReset}>重置</Button>
</div>
</>
);
}
Поскольку схема основана наAnt Design
изForm
компоненты спроектированы таким образом, чтобы сохранитьAnt Design
некоторые функции, разработанныеui
а такжеprops
Два поля соответствуютForm.Item
изprops
и компонентыprops
. даже если последующиеAnt Design
Формы добавляют определенные функции или возможности, и эта схема форм также может поддерживаться без проблем.
2.1.1 Метод проверки
Так как форма основана наAnt Design
реализована, то проверка также использует свою библиотеку классов проверкиasync-validator, эта библиотека классов является относительно зрелой и мощной и может проверятьArray
а такжеObject
и другие типы данных глубокого уровня для удовлетворения потребностей комплексной проверки, поэтому мы вносим коррективы непосредственно на основе этой библиотеки.
пройти черезrules
поля для настройки, кромеasync-validator
В дополнение к уже имеющимся функциям есть дополнительныеstatus
(проверить статус) иtrigger
Перечисление (условие срабатывания) выглядит следующим образом:
- статус: проверить статус
- ошибка (по умолчанию): ошибка
- предупреждение: предупреждение
- триггер: условие триггера
- submit (по умолчанию): срабатывает при отправке
- изменение: инициировать суждение при изменении значения
- размытие: инициировать суждение, когда фокус теряется
Основное использование заключается в следующем:
{
"key": "name",
"type": "Input",
"ui": {
"label": "姓名"
},
"rules": [
{
"required": true,
"message": "姓名必填",
"trigger": "blur",
"status": "error"
}
]
}
2.1.2 Связь
В дополнение к верификации широко используемой функцией также является связывание.Традиционное связывание осуществляется через компоненты.onChange
Когда логика связывания более сложна, смотреть на код так же проблематично, как и искать в связанном списке, поэтому этот блок создает своего рода反向监听
Таким образом, все изменения в поле сохраняются в самой конфигурации поля, что снижает последующие затраты на техническое обслуживание.
пройти черезlisteners
поля настроены, оформленыwatch
(монитор),condition
(условие),set
(Настройки) Комбинация трех полей реализует функцию связи.
watch
Запишите поля, которые необходимо отслеживать, и когда в отслеживаемых полях произойдут какие-либо изменения, он сработает.condition
Условное суждение, только когда условное суждение будет вынесено, оно будет активированоset
настраивать.
[
{
"key": "name",
"type": "Input"
},
{
"key": "gender",
"type": "Radio",
"value": "male",
"options": [
{
"name": "男",
"value": "male"
},
{
"name": "女",
"value": "female"
}
],
"listeners": [
{
"watch": [ "name" ],
"condition": "name.value === 'Marry'",
"set": {
"value": "female"
}
}
]
}
]
В приведенном выше примере, когда имя Marry, пол по умолчанию настроен на женский.
2.1.3 Статус формы
Мы обнаружили, что некоторые сценарии связывания используются для скрытия и отображения полей.Чтобы облегчить пользователям переключение состояний, четыре взаимоисключающих состояния формы объединены в одно.status
Поле:
- статус: статус
- редактировать (по умолчанию): редактировать
- отключено: отключено
- Предварительный просмотр: превью
- скрыто: скрыто
preview
Состояние не принадлежит самому компоненту, но есть много потребностей в предварительном просмотре, поэтому мы сделали расширение для предустановки состояния предварительного просмотра для всех основных компонентов формы. Даже пользовательские компоненты будут отображать значения полей по умолчанию и предоставлять решения, если вам нужно обработать их самостоятельно.
Он используется следующим образом:
[
{
"key": "edit",
"type": "Input",
"status": "edit",
"value": "编辑",
"ui": {
"label": "编辑"
}
},
{
"key": "disabled",
"type": "Input",
"status": "disabled",
"value": "禁用",
"ui": {
"label": "禁用"
}
},
{
"key": "preview",
"type": "Input",
"status": "preview",
"value": "预览",
"ui": {
"label": "预览"
}
},
{
"key": "hidden",
"type": "Input",
"status": "hidden",
"value": "隐藏",
"ui": {
"label": "隐藏"
}
}
]
Схема эффекта выглядит следующим образом:
2.1.4 Настройки параметров
Многие избранные компоненты используютoptions
Поле задает параметры, а параметры иногда получают через асинхронный интерфейс. Учитывая ситуацию с асинхронным интерфейсом, разработаны 4 набора схем:
-
options
дляArray
Случай
{
"key": "type",
"type": "Select",
"options": [
{
"name": "蔬菜",
"value": "vegetables"
},
{
"name": "水果",
"value": "fruit"
}
]
}
-
options
дляstring
случай, ссылка на интерфейс
{
"key": "type",
"type": "Select",
"options": "//api.test.com/getList"
}
-
options
дляobject
Случай,action
для ссылки на интерфейс,nameProperty
настроитьname
поле,valueProperty
настроитьvalue
поле,path
Чтобы получить путь к параметрам,watch
Настройте поле прослушивания
{
"key": "type",
"type": "Select",
"options": {
"action": "//api.test.com/getList?name=${name.value}",
"nameProperty": "label",
"valueProperty": "value",
"path": "data.list",
"watch": [ "name" ]
}
}
-
action
дляfunction
Случай
{
"key": "type",
"type": "Select",
"options": {
"action": (field, form) => {
return fetch('//api.test.com/getList')
.then(res => res.json());
},
"watch": [ "name" ]
}
}
2.1.5 Список форм
Список форм представляет собой составной тип формы, который обычно имеетTable
а такжеCard
Два сценария с функциями добавления и удаления.
Значения формы этого типаArray
возвращается в виде , поэтому конструкцияArray
компоненты, согласноprops.type
правильноTable
а такжеCard
Форма переключается (похоже, что это не так),children
Для настройки подчиненных форм используйте следующие методы:
{
"key": "array",
"type": "Array",
"ui": {
"label": "表单列表"
},
"props": {
"type": "Card"
},
"children": [
{
"key": "name",
"type": "Input",
"ui": {
"label": "姓名"
}
},
{
"key": "age",
"type": "InputNumber",
"ui": {
"label": "年龄"
}
},
{
"key": "gender",
"type": "Radio",
"ui": {
"label": "性别"
},
"options": [
{
"name": "男",
"value": "male"
},
{
"name": "女",
"value": "female"
}
]
}
]
}
Схема эффекта выглядит следующим образом:
2.2 Архитектура фреймворка
Сосредоточившись на идее дизайна схемы, мы приняли схему распределенного управления для разделения основного уровня и уровня рендеринга. Информация о полях хранится на основном уровне. Уровень рендеринга отвечает только за рендеринг, поэтому данные и код интерфейса разделены. .
Переход между основным слоем и слоем рендерингаSub/Pub
способ общения, уровень рендеринга прослушивает серию, определенную базовым уровнемEvent
События вносят коррективы в интерфейс.
Этот тип изменения состояния данных, приводящий к изменениям интерфейса, не является чем-то новым и широко используется в большинстве фреймворков, где преимущества заключаются в следующем:
- Обмен данными и состоянием между полями аспекта
- Благодаря управлению событиями количество визуализаций может быть разумно оптимизировано для повышения производительности.
- Способен адаптироваться к нескольким платформам, нужно только повторно использовать набор кода основного уровня.
Основной слой состоит в основном изForm
,Field
,ListenerManager
,Validator
,optionManager
Он состоит из нескольких частей, как показано на рисунке ниже:
вForm
Это прототип формы, который несет в себе многоField
Полевой прототип, авторListenerManager
Унифицированное управление функциями связи,Field
подValidator
а такжеOptionManager
Управление контрольными суммами отдельноoptions
Опционная функция
2.2.1 Проверка реализации
главным образом черезasync-validator
Библиотека классов реализована, но она по-прежнему не может соответствовать условиям мультипроверки состояния и мультитриггерности, поэтому на ее основе сделаны некоторые расширения, и она упакована вValidator
Добрый.
Validator
единственныйValidator.validate
метод, передаваяtrigger
параметры, инстанцированиеValidator
будет анализироватьrules
поле, согласноtrigger
классифицировать и создавать соответствующиеasync-validator
пример.
2.2.2 Реализация связи
ListenerManager
имеютListenerManager.add
Методы иListenerManager.trigger
методы соответственно для разбора и добавленияlisteners
поля иField
Эффект связи срабатывает при изменении поля.
Конкретный процесс заключается в инициализацииField
, будуlisteners
поле пройденоlistenerManager.add
метод разбора информации, согласноwatch
серединаkey
значение сортируется и сохраняется в нем, когдаField
Когда информация изменится, она пройдетListenerManager.trigger
триггерная связь, суждениеcondition
Выполняется ли условие, если да, то триггерset
содержание.
2.2.3 Реализация списка форм
Список форм фактически состоит из несколькихXForm
Состав экземпляра, каждый элемент автоинкремента представляет собойXForm
например, поэтому связывание может быть выполнено только в одной строке и не может быть связано между строками.
При нажатии кнопки «Добавить» будетchildren
который предоставилSchema
шаблон для созданияXForm
Пример:
2.2.4 Реализация макета
КромеAnt Design
Три метода макета (горизонтальный, вертикальный, встроенный), предоставляемые формой, также должны предоставлять более гибкий метод макета для удовлетворения более сложных ситуаций.
Макет — настоящая головная боль, особенноSchema
в подобномJSON
Внедрение сложных макетов под структуру может легко привести кSchema
Уровень вложенности глубокий, чего мы не хотим видеть.
Исходное решение реализовано через макет сетки, установивForm
изrow.count
илиcol.count
Параметры вычисляют количество строк и столбцов сетки, а затем распределяют поля.Этот метод подходит только для случая, когда количество каждой строки и столбца одинаково, но этот метод трудно удовлетворить ситуацию, когда число каждой строки и столбца несовместимы:
Итак, редизайнui.groupname
поля, то же, чтоgroupname
поля будут заменены наdiv
завернутый, иdiv
изclassName
которыйgroupname
, пользователи могут писать свои собственные стили для создания сложных макетов.Хотя такая схема проста, она практична.
3. Детальный дизайн
3.1 Игнорировать определенные значения полей
Некоторые сценарии следует игнорироватьstatus
дляhidden
Значение поля, поэтому спроектируйтеignoreValues
Поле, конфигурация поля имеет следующие ситуации:
- hidden: игнорировать случаи, когда состояние скрыто
- предварительный просмотр: игнорировать статус предварительного просмотра
- отключено: игнорировать состояние отключено
- null: игнорировать случай, когда значение равно null
- undefined: игнорировать случай, когда значение не определено
- falseLike: игнорирует случаи, когда значение == false
по конфигурацииignoreValues
поле, возвращенное после отправкиvalues
Соответствующие поля игнорируются:
<XForm schema={schema} ignoreValues={['hidden', 'null']}/>
3.2 Деструктуризация и реорганизация полей
Деструктуризация поля относится к разбиению значения поля на несколько полей, а реорганизация поля — к объединению нескольких полей в одно поле Конкретные функции этого блока еще не реализованы, но есть предварительные идеи.
Примеры деструктуризации поля следующие, в основном черезkey
Разделите поле и, наконец, вернитесьvalues
ВключатьstartTime
а такжеendTime
Два поля:
{
"key": "[startTime, endTime]",
"type": "RangePicker",
"ui": {
"label": "时间选择"
}
}
Выявлено, что во многих сценариях необходимо объединить несколько полей в одно поле, в этом случае необходимо написать пользовательские компоненты или обработать данные позже, для упрощения этого процесса реализована функция реорганизации полей. разработан. пройти черезCombine
Компонент реструктурирует несколько полей в одно поле:
{
"key": "time",
"type": "Combine",
"ui": {
"label": "时间选择"
},
"props": {
"shape": "{startTime, endTime, type}"
},
"children": [
{
"key": "startTime",
"type": "DatePicker"
},
{
"key": "endTime",
"type": "DatePicker"
},
{
"key": "type",
"type": "Select",
"options": [
{
"name": "发行时间",
"value": "publishTime"
},
{
"name": "上线时间",
"value": "onlineTime"
}
]
}
]
}
4. Конец
Процесс совершенствования формы продукта — это также процесс изучения сильных сторон других.Мы исследовали конкурирующие продукты в отрасли и разработали этот продукт, исходя из потребностей нашего собственного бизнеса. Идеи и методы реализации схемы формы представлены выше для ознакомления.К сожалению, наш продукт еще не открыт, и я верю, что мы встретимся с вами в нужное время.
5. Сопутствующая информация
Эта статья была опубликована сКоманда внешнего интерфейса NetEase Cloud Music, Любое несанкционированное воспроизведение статьи запрещено. Мы набираем front-end, iOS и Android круглый год.Если вы готовы сменить работу и любите облачную музыку, присоединяйтесь к нам на grp.music-fe(at)corp.netease.com!