Компоненты пользовательского интерфейса представляют собой инкапсуляцию набора связанных взаимодействий и стилей, предоставляя простые методы вызова и интерфейсы, позволяющие разработчикам легко использовать функции, предоставляемые компонентами, для достижения бизнес-требований.
я вAdmin UIизVueБиблиотека компонентов пользовательского интерфейса (адрес GitHub:GitHub.com/B мальчик трепет Y/Ade…библиотека компонентов. Но даже если выReactпользователи , также могут ссылаться на опыт, приведенный в этой статье, потому что, если вы планируете писатьReactбиблиотеки компонентов пользовательского интерфейса, вам придется столкнуться почти с той же проблемой.
Эта статья также является содержанием технического обмена в моей компании. В основном я обсуждаю здесь только идеи и стараюсь не затрагивать конкретные реализации. И мои решения этих проблем не совсем разумны.Если есть какие-то ошибки или неточности, просьба их исправить.
1 Организуйте свой проект
Когда вы начинаете разрабатывать библиотеку компонентов, первое, что нужно сделать, это, вероятно, настроить проект, потому что онVueбиблиотека компонентов, вы, скорее всего, будете использовать ее официальную рекомендациюvue-cliинструмент для создания проекта.
1.1 Соответствующая файловая структура
Когда проект сгенерирован, вы быстро обнаружите, что файловая структура шаблона проекта очень подходит для развития бизнеса, но не очень подходит для разработки библиотек компонентов. В этот момент вы, вероятно,src
Создайте папку с именем вашей библиотеки компонентов в папке для хранения кода вашей библиотеки компонентов. Но на данный момент вы не знаете всего, что нужно сделать, и не настраиваете файловую структуру.
Давайте назовем вашу библиотеку компонентов на данный момент
admin-ui
, чтобы облегчить последующее написание
Когда вы на самом деле начнете писать свой первый компонент, вы обязательно начнете с написания страницы, которая представляет разрабатываемый компонент и тестирует его на ней. Как и тыsrc
создал новую папкуexamples
Папки используются для хранения вашего образца кода.
На данный момент ваша файловая структура выглядит так:
1.2 Напишите или сгенерируйте документацию по использованию библиотеки компонентов
Вполне вероятно, что через какое-то время вы написали пробную страницу для каждого компонента, и некоторые из пробных страниц сами по себе уже потрясающие. Если в один прекрасный день основная разработка библиотеки компонентов будет завершена, эти экземпляры страниц будут бесполезны. Таким образом, вы можете улучшить эти примеры страниц, поместить функции и списки интерфейсов каждого компонента или даже использовать пример кода на их примерных страницах, а затем развернуть его на сервере для просмотра вашими пользователями в любое время. К счастью, они не пропали даром, все они превратились в документацию для библиотеки компонентов!
1.3 Управление документами разработки самой библиотеки компонентов
Тогда вы можете осознать, насколько слаб один человек, и вы приглашаете других разработчиков участвовать в вашем проекте, но даже если вы используетеvue-cliОн уже был включен при создании проектаESlint, но недостаточно полагаться на унификацию стиля кода для совместной разработки полной библиотеки пользовательского интерфейса несколькими людьми. Вам может понадобиться создать документ разработки, в котором вы опубликуете различные соглашения и проекты, а также другую информацию, которой необходимо поделиться. Итак, вы создали новый в корневом каталоге проекта.documentation
каталог и использоватьGitBookДокумент создается и одновременно синхронизируется с сервером GitBook, чтобы ваши друзья могли просматривать его в Интернете, даже если они не синхронизированы.
1.4 Поддержка различных способов установки
Теперь вы готовы приступить к разработке своих компонентов, при написании своего первого компонента вы понимаете, что проект, который вы сейчас пишете, по сути является документацией для вашей библиотеки компонентов, и если это считается бизнес-проектом, то он непосредственно размещает ваш компонент исходный код библиотеки в свой собственный исходный код для использования. Но если другие группы бизнес-проектов используют вашу библиотеку компонентов, они могут только копировать исходный код в свои проекты, как и вы сейчас, и каждый раз, когда ваша библиотека компонентов обновляется, им нужно копировать ее снова. ты. Вы начинаете думать о том, как ваши пользователи устанавливают вашу библиотеку компонентов.
Первое, что приходит на ум, это самый популярный способ установки:npm. Если вы публикуете библиотеку компонентов непосредственно вnpm, ваши пользователи смогут его пройти илиyarnОчень легко установить и обновить. Но в настоящее время ваша библиотека компонентов только начинает работать, и вы не хотите сразу открывать ее исходный код. Итак, вы обратились в компанию за построенным вашей компанией самостоятельноgitlabрепозиторий в , затем в той же папке, где находится ваша библиотека компонентовgit init
инициализировалgitproject и синхронизируйте его с репозиторием, на который вы подали заявку. В это время коллеги по компании уже могут проходить
npm install admin-ui git+ssh://admin-ui-git-location.git --save
Пришло время установить вашу библиотеку компонентов.
Конечно, если компания уже развернула или вы можете развернуть частные репозитории npm в компании, наиболее рекомендуемой практикой является публикация непосредственно в частных репозиториях компании.
Тогда второй метод установки, о котором вы можете подумать, — это CDN. ваши пользователи, встроенные на их страницу
<script src="admin/ui/cdn/location"></script>
Чтобы использовать вашу библиотеку компонентов, необходимо упаковать вашу библиотеку компонентов. В этом сценарии вам необходимо упаковать библиотеку компонентов целиком.admin-ui.js
js-файл, подобный этому. Мы продолжим обсуждение упаковки в следующем разделе.
Конечно, последний способ установки — использовать исходный код напрямую и поместить библиотеку компонентов непосредственно в исходный код проекта для справки.
1.5 Упаковка и публикация вашей библиотеки компонентов
Определив, какие методы установки необходимо поддерживать, вы, возможно, поняли, что теперь есть две части вашего проекта, которые необходимо упаковать и распространить:
- ваша библиотека компонентов (в этом суть)
- Ваше использование библиотеки компонентов документа (то есть самого проекта)
Первое, о чем вы думаете, это то, что очень удобно использовать документацию для упаковки, потому что текущая конфигурация упаковки этого проекта может напрямую упаковать все написанные вами примеры страниц, и единственное, что вам нужно сделать, это запустить
npm run build
Но ключевой проблемой является ваша библиотека компонентов admin-ui. В настоящее время он существует как часть исходного кода вашего проекта. Таким образом, вы должны начать думать о том, как упаковать эту часть кода отдельно.
Конечно, вы также можете не упаковывать свою библиотеку компонентов, а напрямую публиковать ее исходный код в виде пакета npm, но в этом случае пользователям необходимо полагаться на инструменты упаковки для упаковки вашего кода при его использовании. Для проектов, созданных с помощью таких инструментов, как vue-cli, код из папки node_modules не будет упакован по умолчанию.Пользователи должны изменить конфигурацию сборки, чтобы вручную указать расположение кода для упаковки, что очень неудобно.
Итак, вы смотрите наbuild.js
,webpack.prod.conf.js
а такжеprod.env.js
в корневом каталоге проектаbuild
а такжеconfig
добавлено в папкуpublish.js
,webpack.publish.conf.js
а такжеpublish.env.js
файл и ознакомился с документацией по веб-пакету, удалил некоторые ненужные функциональные конфигурации и настроил конфигурацию для упаковки вашей библиотеки компонентов.
Вы ожидаете, что упакованный код будет помещен в папку вашей библиотеки компонентов с именемdist
, то исходные файлы вашей библиотеки компонентов необходимо переместить вsrc
Под содержанием.
Когда webpack упаковывает код, вам нужно указать файл входа.В это время вы обнаружите, что в самой вашей библиотеке компонентов нет файла экспорта.
1.6 Полная загрузка и загрузка по требованию
вы находитесь в библиотеке компонентовsrc
Создал новую папкуindex.js
файл, который импортирует и экспортирует все компоненты.
import Button from './components/button'
import Icon from './components/icon'
// ...省略的代码...
export {
Button,
Icon
// ...省略的代码...
}
На этом этапе вы можете просто спланировать файловую структуру самой библиотеки компонентов:
В этом формате вывода ваши пользователи могут
import { Button } from 'admin-ui'
чтобы получить компонент Button из библиотеки компонентов. Однако это только поддержка данного формата (это не загрузка по требованию), пользователям также необходимо иметь возможность выполнять полную загрузку, то есть вводить сразу все компоненты и регистрировать их все автоматически. Как и тыindex.js
Установите все компоненты вadminUi
объект, а затем смонтировать на этом объектеinstall()
метод поддержкиVue.use()
и, наконец, вывести объект напрямую. теперь твойindex.js
Это выглядит так:
import Button from './components/button'
import Icon from './components/icon'
// ...省略的代码...
export {
Button,
Icon
// ...省略的代码...
}
const adminUi = {
Button,
Icon,
// ...省略的代码...
}
adminUi.install = function (Vue, options = {}) {
Vue.component('cu-button', Button)
Vue.component('cu-icon', Icon)
// ...省略的代码,你也可以用循环来写...
}
export default adminUi
install()
В методе много чего можно сделать, кроме регистрации компонентов, вполне вероятно, что вы еще и монтируете в нем какие-то экземплярные методы
На этом этапе ваши пользователи могут
import adminUi from 'adminUi'
Vue.use(adminUi)
для полной загрузки.
Следующим шагом является загрузка по запросу. вы обнаружите, что если только через вашindex.js
Входной файл используется для загрузки определенного компонента.Хотя другие компоненты не вводятся пользователем, они все же компилируются в пользовательский код. Так что придется думать о новых способах. Поскольку его нельзя загрузить из одной точки входа, можно ли указать точку загрузки для каждого компонента? Вы хотите, чтобы ваши пользователи могли
import Button from 'admin-ui/button'
Загрузите один компонент таким образом, чтобы не было лишних компонентов. Таким образом, вы понимаете, что каждый компонент также должен быть упакован отдельно. Экспорт файлов для каждого компонента (вероятно, такжеindex.js
Здесь следует понимать, что файловую структуру каждого компонента можно последовательно привести к пакету, упаковать каждый компонент в отдельный модуль, чтобы разместить его.dist
серединаlib
под папку. В настоящее время поддерживается загрузка по запросу.
Конкретную настройку вебпака я не обсуждал.Во-первых, в этой статье в основном обсуждаются идеи, а не конкретная реализация.Во-вторых, если эту тему нужно обсудить подробно, то потребуется больше места.В-третьих, настройка самого вебпака очень сложна и я не умею.
Затем вы с удовольствием попытались упаковать, но с разочарованием обнаружили, что независимо от того, использовали ли вы экспортный файл самой библиотеки компонентов в качестве записи или когда вы упаковывали каждый компонент по отдельности, результат был почти один..js
файл, также будет.css
документ. Независимо от того, загружаются ли ваши пользователи полностью или загружаются по запросу, когда вы вводите.js
Соответствующий файл также должен быть введен.css
документ. При полной загрузке, поскольку он загружается только один раз, это не имеет большого значения. Но если он загружается по запросу, это немного проблематично, потому что его нужно вводить несколько раз.
Отдельный файл css предназначен для повышения производительности, файл css может кэшироваться браузером, а самому компоненту не нужно генерировать css при рендеринге.
Есть два решения, одно из которых — рекомендовать пользователям использоватьbabel-plugin-component, другой заключается в том, что сам упакованный компонент больше не предоставляет файл css, но полностью загруженный файл css вводится глобально. Любой подход работает, но я использую последний.
Причин две: во-первых, стили компонентов невелики по размеру, и они контролируются в пределах 60 КБ после сжатия и упаковки (большинство из которых — шрифтовые коды стилей, а все стили компонентов не превышают 5 КБ). ; во-вторых, потому что с font-awesome, если каждый компонент вводит свой собственный стиль, компоненты, зависящие от font-awesome, будут иметь повторяющиеся стили.
2 Создайте систему тем
Когда ваша библиотека компонентов используется в разных проектах или для определенного проекта требуется функция создания скинов, неизбежно вам необходимо разработать систему тем в вашей библиотеке компонентов.
2.1 Определение функциональных границ предметной системы
Прежде всего, вам необходимо уточнить границы системных функций вашей темы. На мой взгляд, есть три основных фактора, влияющих на стиль фоновой системы управления:
- Цвет (это главное)
- тень
- закругленные углы
Итак, давайте начнем с установки границ вашей системы тем для этих трех факторов.
2.2 Выберите правильную реализацию
Затем вы начинаете думать о возможных идеях реализации системы тем:
- Замена строки в специальном формате
- Предварительно скомпилированные файлы темы
- класс стиля
Замена строки в специальном формате, несомненно, является самым простым.Когда вы сталкиваетесь со стилем, который должен контролироваться системой тем во время разработки, вы можете напрямую использовать строку специального формата в CSS и заменить ее во время выполнения. Например:
div {
color: ?primary?;
}
Среда выполнения заменяется вашим скриптом на:
div {
color: #00f;
}
Преимущество этого решения в том, что оно очень удобно в разработке, в принципе не влияет на опыт разработки и даже улучшает. Не такая уж большая проблема в традиционную эпоху jquery, но что касается проектов Vue, существует проблема «времени замены». Вы можете поместить все страницы на страницу после инициализации проекта<style>
специальные символы в тегах заменяются, но при изменении страницы новый компонентstyle
вставляется вhead
В середине тоже нужно снова произвести замену, а найти подходящий момент для этого сложно.
Предварительная компиляция файла темы в настоящее время является основным решением для реализации темы на рынке. То есть сама библиотека пользовательского интерфейса предоставляет инструменты для генерации файлов CSS разных тем, и заранее компилируется несколько наборов файлов разных стилей темы. Преимущество в том, что он прост и понятен, удобен и прост в использовании. Но недостатки тоже очевидны: замена тем во время выполнения становится очень грубой (крупнозернистой) — заменять можно только целые наборы.
Класс стиля предназначен для разработки правил стиля и применения класса стиля к необходимым элементам:
.au-theme-font-color--primary {
color: #00f;
}
<p class="au-theme-font-color--primary">主色</p>
Класс стилей также имеет свои весьма очевидные дефекты: во-первых, нужно иметь очень четкое оформление правил класса стилей, а затем влияние на разработку также очень существенное: все стили, охватываемые системой тем, могут только быть написано в классе стиля, а не напрямую написано в css. Эти два момента налагают на пользователей определенные когнитивные и эксплуатационные нагрузки. Но преимущества также очевидны: степень детализации управления может быть очень тонкой, нет проблемы синхронизации замены, и в то же время можно напрямую использовать не только тему самой библиотеки компонентов, но и весь проект.
Экспериментально я выбрал класс стиля, так что предположим, что вы сделали тот же выбор.
2.3 Использование классов стилей для разработки и реализации вашей системы тем
Если вы не знаете, с чего начать, попробуйте начать с точки зрения пользователей вашей системы тем. Вы ожидаете, что ваши пользователи смогут управлять темой с помощью простой функции:
adminUi.theme(config)
тогда, естественно, вы определяетеconfig
Структура. В соответствии с ранее определенной системной функцией темы вы определите ее следующим образом:
const config = {
colors: {
'base-0': '#000',
'base-1': '#232a29',
'base-2': '#2f3938',
'base-3': '#44514f ',
'base-4': '#616e6c',
'base-5': '#7c8886',
'base-6': '#b1bbba',
'base-7': '#d9dedd',
'base-8': '#eaf0ef',
'base-9': '#f3f7f6',
'base-10': '#f7fcfb',
'base-11': '#fdfdfd',
'base-12': '#fff',
'primary-top': '#01241d',
'primary-up': '#3fd5b8',
'primary': '#19bc9d',
'primary-down': '#169f85',
'primary-bottom': '#e7f7f4',
'info-top': '#011725',
'info-up': '#f0faf8',
'info': '#3498db',
'info-down': '#2d82ba',
'info-bottom': '#e6f3fc',
'warning-top': '#251800',
'warning-up': '#fec564',
'warning': '#ffb433',
'warning-down': '#e99b14',
'warning-bottom': '#fbf3e5',
'danger-top': '#220401',
'danger-up': '#f56354',
'danger': '#e74c3c',
'danger-down': '#c33a2c',
'danger-bottom': '#fae7e5',
'success-top': '#012401',
'success-up': '#7fcb7f',
'success': '#5cb95c',
'success-down': '#3da63d',
'success-bottom': '#e7fae7'
},
shadows: {
'base': '0 1px 4px rgba(0, 0, 0, .2)',
'primary': '0 0 4px rgba(25, 188, 157, .6)',
'info': '0 0 4px rgba(52, 152, 219, .6)',
'warning': '0 0 4px rgba(255, 180, 51, .6)',
'danger': '0 0 4px rgba(231, 76, 60, .6)',
'success': '0 0 4px rgba(92, 185, 92, .6)'
},
radiuses: {
'small': '2px',
'large': '5px'
}
}
-
primary
,warning
,danger
,info
,success
основной цвет -
[COLOR]-up
,[COLOR]-down
Это вторичный цвет, светлота которого ближе к основному цвету. -
[COLOR]-top
,[COLOR]-bottom
Это вспомогательный цвет с большим отличием по яркости от основного цвета. -
base-0
,base-12
самый темный ахроматический и самый яркий ахроматический -
base-[1~11]
ахроматический (серый), отсортированный по светлоте
Причина, по которой не используются слова с информацией о цвете (например, светлый, темный-первичный и т. д.), а используются числа и направления в качестве названий цветов, заключается в том, чтобы облегчить пользователям определение любого цвета по имени, если вы поместите название чистого черного. как темный, но пользовательская конфигурация #fff чисто белая, это имя приведет к недоразумению. В ахроматических цветах мы используем числа в качестве имен, а в цвете мы используем направления в качестве имен, которые могут не только соответствовать иерархическому дизайну цвета, но и избегать двусмысленности.
Ваш набор правил конфигурации предполагает, что пользователи будут настраивать цвета в соответствии с яркостью, а расположение светлоты каждого типа цвета является согласованным. Это сделано для облегчения смешения светлых и темных цветов, например, светлый текст следует использовать на темном фоне. Но с этим ограничением преимущество заключается в том, что пользователи могут настраивать некоторые собственные цвета.
В то же время, чтобы еще больше упростить настройку цвета, вы решили использовать значения по умолчанию теней, неосновных цветов и ахроматических цветов на основеprimary
цвета и некоторые вспомогательные настройки для их автоматического расчета. Таким образом, фактическая конфигурация пользователя может быть дополнительно упрощена:
export default {
theme: {
colors: { // 彩色配置
primary: '#1c86e2',
info: '#68217a',
warning: '#f5ae08',
danger: '#ea3a46',
success: '#0cb470'
},
shadows: { // 阴影配置
// primary: '0 0 4px #1c86e2',
// info: '0 0 4px #68217a',
// warning: '0 0 4px #f5ae08',
// danger: '0 0 4px #ea3a46',
// success: '0 0 4px #0cb470'
},
radiuses: {
small: '3px',
large: '5px'
}
},
lightnessReverse: false, // 反转lightness排序(黑白主题)
colorTopBottom: 5, // top和bottom颜色距离纯黑和纯白的lightness的距离,越小越接近纯黑纯白
colorUpDown: 10, // 彩色上下接近色与正色的lightness距离
baseColorLeve: 12, // 无彩色分级数量
baseColorHue: '20%', // 无彩色饱和度
baseShadowOpacity: 0.2, // 无彩色阴影不透明度
colorShadowOpacity: 0.6 // 彩色阴影不透明度
}
Структура файловой системы темы выглядит следующим образом:
Затем подумайте о том, как пользователи будут применять систему тем к элементам после ее настройки. Классы стилей, предоставляемые вашей системой тем, нуждаются в запоминаемом синтаксисе для удобства пользователей. В настоящее время вы можете разработать синтаксические правила, подобные следующим:
前缀 [-伪类名] -属性名 --属性值 [-权重]
- префикс: префикс класса стиля темы
- имя псевдокласса: необязательно, если тема применяется к псевдоклассу текущего элемента, вы можете конкатенировать имя псевдокласса в имени класса
- имя атрибута: имя атрибута стиля
- Значение атрибута: значение атрибута стиля, то есть имя, настроенное в конфигурации.
- вес: необязательный, используйте его, чтобы добавить стиль к этой теме
!important
суффикс
В соответствии с этим набором правил грамматики пользователи используют его следующим образом:
<div class="
au-theme-background-color--base-12
au-theme-border-color--primary
au-theme-font-color--base-3
au-theme-box-shadow--base
au-theme-radius--small"></div>
Наконец, ваша система тем преобразует конфигурацию, переданную пользователем, в определенные коды классов стилей в соответствии с вашими грамматическими правилами и использует<style>
Тег вставляет его на страницу.
3 Предоставьте набор компонентов формы
Любая библиотека компонентов пользовательского интерфейса, особенно библиотека компонентов пользовательского интерфейса для систем управления, неизбежно должна предоставлять набор компонентов формы. Причина очень проста: во-первых, элементы управления формой по умолчанию, предоставляемые различными браузерами, не только отличаются по стилю, но и уродливы, во-вторых, функции верстки и проверки форм просто необходимы, и нет причин не абстрагироваться от них. .
Итак, прежде всего, вы перечислите часто используемые компоненты формы: поле ввода текста, множественный выбор, одиночный выбор, переключатель, раскрывающийся список, каскад, дата, время, загрузка файла, эти компоненты помещаются вами в СПИСОК TODO. .
3.1 Единый интерфейс формы
Вы обнаружите, что многие компоненты формы ведут себя одинаково, например, требуютvalue
интерфейс, должен поддерживатьv-model
, обеinput
илиchange
события и т.д. Эти унифицированные поведения лучше всего сочетать вместе, поэтому вы можете использовать Vue’smixin
Функция для извлечения этих унифицированных поведений вместе, с одной стороны, проста в управлении, а с другой стороны, она может сделать функцию и поведение компонентов формы максимально согласованными, чтобы снизить когнитивные затраты пользователей. .
3.2 Единый метод проверки
Фактически, эта часть функции проверки строго говоря, она может рассматриваться как единый интерфейс формы, поэтому он также может быть помещен в вышеуказанный файл, но логика верификации является относительно независимой, поэтому вы, вероятно, отделить его и сделайте еще одинminxin
справляться.
Если вы много пишете формы, нетрудно обнаружить, что на самом деле есть только два случая, когда дело доходит до проверки:
- Интерактивная проверка: когда пользователь заполняет элемент формы, запускается проверка этого элемента.
- Проверка отправки: пользователь запускает проверку всех элементов всей формы при отправке.
Поддерживать интерактивную аутентификацию на самом деле очень просто, и этого можно добиться, просто используя события. Для поддержки проверки отправки каждый компонент формы должен предоставлять определенные методы проверки для внешних вызовов, например:this.$refs.$userNameInput.validate()
, результат проверки можно получить, вызвав эту функцию извне, при отправке формы метод проверки всех компонентов формы можно вызвать один раз.
И когда ваша программа запускает проверочный код, возможны две ситуации:
- Синхронная проверка
- Асинхронная проверка
Поддерживать синхронную проверку очень просто, просто вызовите заданную внешнюю функцию проверки правильности, а затем верните ее результат. Но если это асинхронная проверка, это будет более хлопотно. Давайте копнем немного глубже, предположив, что в настоящее время пользователь указал что-то вроде<au-input/>
Валидатор для:
<au-input
:validatiors="[
{
validator (v) { return v > 0 },
warning: '必须大于0'
}
]"/>
Когда вы получаете валидатор, вы не можете знать, синхронный он или асинхронный, поэтому вы можете попросить пользователя указать синхронный или асинхронный:
<au-input
:validatiors="validators"/>
export default {
data () {
return {
validators: [
{
validator (v) { return v && v.length && !/^\s*$/g.test(v) },
warning: '不能为空'
},
{
validator () {
return new Promise(resolve => {
axios.get('is-duplicated-name')
.then(data => resolve(data.result))
})
},
warning: '已经有重复的名字了',
async: true
}
]
}
}
}
Когда пользователь указывает синхронную или асинхронную проверку, как указано выше, и функция проверки возвращаетpromise
После этого можно заранее разделить все валидаторы на две категории: синхронная валидация и асинхронная валидация, и валидировать сначала синхронные функции, а если будут какие-то неудачные валидации, можно не валидировать асинхронные функции для уменьшения накладных расходов. Ниже приведена моя логика проверки в пользовательском интерфейсе администратора, которая выпущена для вашего ознакомления:
// the common validation logic of enhanced form components
export default {
// ... 省略的代码 ...
methods: {
validate () {
let vm = this
if (vm.warnings && vm.warnings.length) return false
if (!vm.validators) return false
// separate async and sync
let syncStack = []
let asyncStack = []
vm.validators.forEach((v) => {
if (v.async) {
asyncStack.push(v)
} else {
syncStack.push(v)
}
})
// handler warnings
let handleWarnings = (res, i, warning) => {
if (!res) {
vm.$set(vm.localWarnings, i, warning)
} else {
vm.$delete(vm.localWarnings, i)
}
}
return new Promise((resolve) => {
let asyncCount = asyncStack.length
// execute sync validation first
syncStack.forEach((v, i) => {
handleWarnings(v.validator(vm.value), i, v.warning)
})
// if sync validation passed, execute async validationg
if (!vm.hasLocalWarnings) {
if (asyncCount <= 0) { // no async
resolve(!vm.hasLocalWarnings)
} else {
Promise.all(asyncStack.map((av, i) => {
return av.validator(vm.value).then(res => {
handleWarnings(res, i, av.warning)
})
})).then(results => {
if (results.includes(false)) resolve(!vm.hasLocalWarnings)
else resolve(!vm.hasLocalWarnings)
})
}
} else { // if sync validation failed
resolve(!vm.hasLocalWarnings)
}
})
}
}
}
Метод проверки компонента формы возвращаетpromise
,В егоresolve
Конкретный результат проверки возвращается в методе.Преимущество в том, что при отправке проверки пользователю не нужно различать синхронный и асинхронный, и все обрабатываются единообразно, что просто и удобно:
export default {
validateAllFormitems () {
Promise.all([
this.$refs.name.validate(),
this.$refs.age.validate(),
this.$refs.gender.validate()
]).then(results => {
if (!results.includes(false)) this.submit()
})
}
}
3.3 Компоновка упаковки
Существует два распространенных расположения форм: одно — расположение меток и элементов формы вверх и вниз, а другое — расположение слева и справа. Компоновка компонентов формы должна быть согласованной, поэтому для этого можно создать компонент-контейнер компонентов формы. Разумеется, в вашем интерфейсе компонента формы также должен быть соответствующий интерфейс для управления набором текста.
При расположении вверх и вниз, в дополнение к обычной ширине, такие компоненты, как поля ввода текста и раскрывающиеся поля выбора, также должны учитывать ширину 100%. На этом этапе вам может понадобиться другойfull-width
Интерфейс, позволяющий пользователю выбирать, заполнять ли его на всю ширину.
При расположении слева и справа учитывайтеlabel
выравнивание. Общей практикой является указание, что все элементы формы имеютlabel
до подходящей ширины, послеlabel
Текст выравнивается по правому краю. Поскольку сами компоненты не зависят друг от друга, вы должны ожидать, что пользователь скажет вамlabel
, поэтому каждый из ваших компонентов формы предоставляетlabel-width
интерфейс.
Вы инкапсулируете эти функции вform-item
в компоненте-контейнере и используйте его в каждом компоненте формы.
3.4 Даты, время и диапазоны дат и времени
Что касается компонентов, соответствующих трем функциям даты, времени и диапазона даты и времени, я надеюсь, вы сможете подумать над вопросом: как разделить функции компонентов.
Общее деление это
- Выбор даты: вы можете выбрать дату одной точки или диапазон дат.
- Селектор времени: вы можете выбрать время в одну точку или временной диапазон
- Выбор даты и времени: вы можете выбрать дату и время одной точки или вы можете выбрать диапазон даты и времени.
Тем не менее, мой более рекомендуемый дивизион
- Выбор даты: можно выбрать только одну точечную дату
- Выбор времени: можно выбрать только одно момент времени
- Выбор диапазона даты и времени: можно выбрать только диапазон, но это может быть просто диапазон дат, или только диапазон времени, или диапазон даты и времени.
Преимущество этого разделения заключается в том, что ваши средства выбора даты и времени могут быть повторно использованы в максимальной степени, а реализация трех компонентов намного проще, чем три компонента в предыдущем разделе. Это не просто понять, нужно разбираться внимательно.
4 Предоставьте набор библиотек значков
Большинство библиотек пользовательского интерфейса предоставляют компоненты значков. Причина проста: никому не нравится эта надоедливая проблема пути к файлу шрифта. Представление файла шрифта через фиксированный компонент может спасти ваших пользователей от его ловушки.
В более ранних версиях пользовательского интерфейса администратора использовался более красивыйIoniconsБиблиотека иконок, но ее типов иконок немного меньше, а последующие версии заменены наFont AwesomeБиблиотека иконок.
Какой значок вы выберете, не имеет большого значения.Вы даже можете не использовать стороннюю библиотеку значков, а только предоставить минимальный набор значков, требуемый вашей библиотекой компонентов, и оставить выбор, какую библиотеку значков использовать, вам. Компонент user-icon должен поддерживать использование сторонних значков.
5 Необходимые системы сетки
Почти большинство библиотек пользовательского интерфейса на рынке поставляются с системой сетки, которая позволяет разработчикам быстро адаптироваться к страницам макета. Более ранние технологии, такие как библиотеки пользовательского интерфейса, такие как Bootstrap, используютfloat
а такжеwidth
и другие свойства CSS и медиа-запросы CSS для реализации системы сетки. И современные библиотеки пользовательского интерфейса в основном используютflex
реализовать сетку.
Возможно, вы захотите использовать современные методы для реализации системы сетки, такой как Bootstrap. Однако в Bootstrap использование сеток зависит от классов стилей, которым требуется родительский элемент и несколько дочерних элементов для формирования необходимой структуры. Вы можете быть недовольны этим. Применение классов стиля может использоватьprops
Вместо этого фиксированный родительский элемент, о котором вы, вероятно, не хотите, чтобы пользователь заботился. Для этого вы рассматриваете возможность использования только одногоgrid
компоненты для реализации всей системы сетки, поэтому при инициализации вам необходимо иметь дело с родительским элементом, особенно необходимость иметь дело с родительским элементом предполагает использованиеdisplay
Свойство, поскольку вам нужно всегда использовать его на родительском элементеflex
Атрибуты.
Вполне возможно использовать медиа-запросы иflex
свойства для завершения системы сетки. Но когда дело доходит до интервалов, это может быть сложно реализовать с помощью CSS.flex
Свойства могут обеспечить характеристики горизонтального расположения сетки, но ширины самой сетки, поскольку она включает в себя расчет интервалов, вы можете использовать для этого JavaScript.
пользователь черезprops
проходить вwidthLg
Свойства , сообщают количество сеток, занимаемых компонентом под большим экраном, черезspace
Свойство сообщает расстояние между компонентом и следующим компонентом. В это время необходимо ввести понятие строки. Вам нужно рассчитать, какие компоненты находятся в строке, потому что последний в конце строкиgrid
С правой стороны не может быть места, иначе оно будет сжато до следующей строки, потому что превышает общую ширину одной строки.
Реализация сетки не сложна, главное требование — это характеристики самой сетки: количество сеток, занимаемых экранами разной ширины, расстояние смещения и шаг. Вы понимаете, я не собираюсь говорить о конкретной реализации, но вы можете пойти и посмотретьисходный кодпроверить это. Честно говоря, реализация этой части не элегантна, в основном какие-то экспериментальные практики. Добро пожаловать на рефакторинг!
6 Модульное тестирование и интернационализация
Честно говоря, я не буду говорить об этой части. Но вы должны знать, что если ваша библиотека компонентов будет в будущем с открытым исходным кодом, эти две части необходимы.
7 Заключение
Если принять во внимание конкретные детали реализации, то эта статья по сути не имеет никакого отношения. Я просто перечислил проблемы, с которыми вам нужно столкнуться, чтобы написать библиотеку компонентов, и рассказал о решениях в целом. В любом случае, надеюсь, что это может вдохновить вас.
В конце концов, даже в сборке колес есть свое удовольствие. Сначала выкопайте дыру здесь.В будущем я могу выбрать некоторые интересные компоненты из компонентов и написать еще одну статью, чтобы поделиться подробностями реализации конкретных компонентов, так что следите за обновлениями~
В то же время вы также можете разветвить эту библиотеку пользовательского интерфейса, полную личных вещей.