Самое простое решение для создания скинов Ant-Design

Ant Design
Самое простое решение для создания скинов Ant-Design

предисловие

Адрес онлайн-просмотра:Dynamic-Antd-Theme-Demo Вроде все в порядке, если вы знаете, как им пользоваться, думаю, вы подумаете, что я не титульный участник.

// 如何使用
import DynamicAntdTheme from 'dynamic-antd-theme';

render() {
    ...
    <DynamicAntdTheme />
    ...  
}

Всё верно, всё так просто.Для удобства всех я сделал plug-and-play компонент.Добро пожаловать в звезду+выпуск+пр.dynamic-antd-theme

Почему муравьиные решения для снятия скинов

Вот что я хочу сказать, я не был достаточно тщеславным или жадным, чтобы иметь возможность реализовать идеальное и разумное решение для динамического скининга. например, сообщество с открытым исходным кодомantd-theme-webpack-pluginиantd-theme-generatorЭто очень зрелое решение, которое использует веб-пакет для реализации динамического скина, добавляя на страницу less.js, что очень тщательно.

Так почему же я должен делать так называемый динамический скиннинг? Причины следующие:

  • Во-первых, две приведенные выше схемы не охватывают все сценарии, нужные ему входные файлыindex.html, как участник nextjs, я не мог найти его, как бы я ни искал, поэтому я не смог успешно настроить его в своем проекте поддержки nextjs.
  • Во-вторых, я лично считаю, что конфигурация и использование немного громоздки и вводят слишком много дополнительного контента. В html-файл должен быть добавлен файл less.js, потому что тогда тему можно будет динамически менять с помощью window.less. Так же есть различные css файлы, которые не очень понятны при настройке.
  • Наконец, и самое главное. Кто-то задал вопрос в моей статье, который связан сNext-Antd-ScaffoldЕсли вам интересна эта статья о строительных лесах, вы можете перейти к статье, которую я написал ранее. Маленький друг не был успешно настроен и не имеет никаких идей. Что мне делать? Как автор-энтузиаст, я должен помочь решить эту проблему~

Вот Амвей,Next-Antd-ScaffoldВ настоящее время базовая разработка завершена.Я также использую эту полку для написания проектов.Многие мелкие партнеры также пишут проекты.Все должно быть в порядке.Студенты, которые заинтересованы в Nextjs, могут присоединиться к группе WeChat внизу статьи общаться вместе~ Самое главное , ты ставишь мне звезду, я стараюсь изо всех сил решить проблему, 😄

Подводя итог, я провел выходные, чтобы придумать решение plug-and-play и скинов, которое можно установить и использовать одним щелчком мыши. Конечно, раз уж это так просто, должны быть и недостатки, ведь моя тема - это самое простое решение и решение для скинов, а не самое совершенное решение для скинов. Послушайте меня подробно.

Процесс реализации

Для конкретного процесса реализации я объясню идеи, решения, детали и трудности, а также недостатки проекта.

Все мои примеры здесь черезNext-Antd-Scaffoldписать~

идеи

Давайте сначала поговорим об идеях, поскольку я хочу быть нестандартным и максимально простым решением и скиннингом, не должно быть сложного процесса настройки и неясных документов. Конечно, если честно, до того, как я глубоко прочитал исходники и механизм вебпака, у меня не получалось писать плагины на уровне двух вышеперечисленных, ха-ха 😄.

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

Взяв в качестве примера кнопку button, вы можете видеть, что мы установили@primaryColor = #524c1a, имя класса.ant-btn-primary, тогда давайте покроем это.

// 样式变换代码
const styleDom = document.createElement('style');
styleDom.innerHTML = `
    .ant-btn-primary {
        border-color: #0000ff;
        background-color: #0000ff;
    }
`;
document.getElementsByTagName('head')[0].appendChild(styleDom);

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

план

Благодаря вышеприведенной практике мы определили идею, и здесь мы определим осуществимый план. Честно говоря, большинство фронтенд-разработчиков должны уметь думать о проблеме покрытия имён классов, а некоторые люди должны этим пользоваться, ведь потребность в скиннинге — базовое требование многих мидл- и бэкенд-систем, но даже покрытие имени класса у разных людей разное, а сложность переопределения имени класса в том, что хорошо перезаписать базовый цвет, если для каждого элемента псевдокласса типа:hover :active :focusПокрытие подходящего цвета не только сложно в реализации, но и требует много работы. Я думаю, что здесь я реализую для вас универсальную схему покрытия имен классов, вам больше не нужно реализовывать громоздкую постраничную реализацию или модифицировать файлы css различными способами, вам нужно только ввести этот плагин для автоматического convert охватываются все классы.

Конкретный процесс реализации

  • Извлечь все связанные с цветом классы antd

    я кладуantd-v3.19.0版本Файл css скачан на локалку, там около 2W+ строк кода, из которого я бережно и терпеливо извлек все@primaryColorродственные цвета (включая:hover :focus :active)Ждать. Поскольку в классе сохраняются только связанные с цветом атрибуты, он сокращается примерно до 900 строк кода.

    Вот простой скрин, показывать не буду, если хотите посмотреть, адрес сюдаtheme.css.

    Дело здесь в том, что,:root{ ... }Следующие переменные цвета можно считать дизайнерскими решениями, потому что таким образом мне нужно только получить цвет, установленный пользователем, а затем сгенерировать соответствующий цвет для замены переменной colorVar. В противном случае мне нужно написать регулярку, чтобы соответствовать всем цветам, эффективность определенно не так хороша, как эта

  • Динамически получить пользовательский цвет, а затем заменить

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

    const cssVar = `
      :root {
          --primary-color: ${primaryColor};
          --primary-hover-color: ${hoverColor};
          --primary-active-color: ${activeColor};
          --primary-shadow-color: ${shadowColor};
      }
    `;
    // 给插入的标签赋id,避免多次插入<style>
    let styleNode = document.getElementById('dynamic_antd_theme_custom_style');
    if (!styleNode) {
      // avoid repeat insertion
      styleNode = document.createElement('style');
      styleNode.id = 'dynamic_antd_theme_custom_style';
      styleNode.innerHTML = `${cssVar}\n${cssContent}`;
      document.getElementsByTagName('head')[0].appendChild(styleNode);
    } else {
      styleNode.innerHTML = `${cssVar}\n${cssContent}`;
    }
    

    Содержание вышеуказанной этикетки:<style>${cssVar}\n${cssContent}</style>,cssVarнесколько переменных, связанных с цветом, который мы определяем, а затемcssContentэто весь код css, который я извлекtoString()Он сразу становится строковой переменной.

    Чтобы получить цвет динамически, я используюreact-colorЭтот подключаемый модуль, а поскольку он создает скин, должен сохранять выбранный пользователем план, поэтому соответствиеlocalStorageПри кэшировании на стороне клиента конечный результат таков:

Кто-то, возможно, сказал это, вы сказали это в течение длительного времени@primaryColorРодственные цвета, пока есть только один@primaryColor, вы тут чушь несете, 😄 Не волнуйтесь, я уже говорил, что это самое важное место, и его нужно поставить в трудное место.

трудность

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

Любой, кто использовал это здесь, должен понять, что я имею в виду, кнопка кнопки antd, метка и т. Д.,:hover/:focus/:active/:visitedи т. д. Все эти свойства имеют свои цвета, некоторые связаны с@primaryColorПо сравнению с более мелкими, некоторые из них с@primaryColorПо сравнению с более темным ~ см. следующую анимацию для деталей, цвет светлее при наведении курсора и темнее при активном

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

Глядя на исходный код antd, можно обнаружить, что он тут ни при чем.:hover :active :focusДетальные настройки цветов, но пропускаются все цвета@primaryColorпреобразован.

Как видите, будет@primaryColorделится на цветовой уровень, сlevel6как разделительная линия,<6цвет будет сравниваться с@primaryColorнеглубокий, подходит для:hoverэто,>6цвет будет@primaryColorглубже, подходит:activeЭтот вид. Все цвета черезcolorPaletteЭтот метод генерируется, поэтому мы поговорим об этом подробно.

Я приложил все усилия, чтобы понять и попытаться сделать заявление заранее и бросить горшок, но в итоге я понял только четыре простых цвета, и он не был разделен на 10 уровней, как раньше.Если вам это не нравится, не Не распыляйте его. Если вы заинтересованы, вы можете упомянуть PR и получить его. Становится все лучше и лучше ~

/**
 * 下面这些代码谨代表我个人的事先过程以及能力水平
 * 我没仔细看官方实现,所以antd肯实现的更高级
 **/
// 获取hover的浅颜色
function getHoverColor (color, index = 5) {
  return tinycolor.mix(
    '#ffffff',
    color,
    currentEasing(index) * 100 / primaryEasing
  ).toHexString();
}
// 获取active的深颜色
function getActiveColor (color, index = 7) {
  return tinycolor.mix(
    '#333333',
    color,
    (1 - (currentEasing(index) - primaryEasing) / (1 - primaryEasing)) * 100
  ).toHexString();
}

Выше есть две функции: одна для получения светлого цвета, а другая для получения темного цвета. Обе функции вызываются внутри функцией с именемtinycolor.mixметод, и это очень легко понять, когда мы смотрим на параметры, этоmixМетод на самом деле состоит в том, чтобы сделать наш основной цвет@primaryColorДля смешивания с другим цветом, например, с#ffffffЧтобы интегрировать, даже если я не знаю кода и не разбираюсь в компьютере, любой, кто научился рисовать, должен знать, что если есть цвет, смешанный с белым, цвет станет светлее, но другим он не станет. цвета, то есть蓝色 -> 浅蓝色,红色 -> 浅红色Подождите, другой делает то же самое, с#000000Он будет углубляться, когда черные и серые линии сольются. смотри это дальшеmix函数了:

/* tinycolor-mix */
tinycolor.mix = function(color1, color2, amount) {
  amount = (amount === 0) ? 0 : (amount || 50);

  var rgb1 = tinycolor(color1).toRgb();
  var rgb2 = tinycolor(color2).toRgb();

  var p = amount / 100;

  var rgba = {
    r: ((rgb2.r - rgb1.r) * p) + rgb1.r,
    g: ((rgb2.g - rgb1.g) * p) + rgb1.g,
    b: ((rgb2.b - rgb1.b) * p) + rgb1.b,
    a: ((rgb2.a - rgb1.a) * p) + rgb1.a
  };
  return tinycolor(rgba);
};

Здесь нужно ввести два цвета и вес и, наконец, вывести значение цвета rgba. здесьtinycolorЭто плагин, связанный с цветом, вы можете посмотреть, если вам интересно.

хорошо, тогда что это за вес?Если честно, я не очень силен в математике, поэтому я действительно не понимаю этого.В любом случае, это байесовская кривая, просто чтобы сделать наше преобразование цвета более плавным~ Другие статьи Объяснение наверное вот так, и есть картинка:

Я не буду здесь вдаваться в подробности, да и не понимаю этого, во всяком случае, я нарисовал его после кота и тигра. Следует подчеркнуть, что для кривой необходимо выбрать базовую линию.Базовая линия antd выглядит следующим образом:

/* basic-easiing */
const baseEasing = BezierEasing(0.26, 0.09, 0.37, 0.18);

// 主色基线
const primaryEasing = baseEasing(0.6);
// 融合颜色的基线
const currentEasing = index => baseEasing(index * 0.1);

Я не знаю, если я не ясно дал понять.После вышеуказанной сложной серии операций вы можете сгенерировать соответствующее значение цвета основной цветовой системы в соответствии с введенным вами основным цветом, а затем заменить его на cssVar~

Другие особенности

Вы можете использовать его напрямую:

npm install dynamic-antd-theme
or
yarn add dynamic-antd-theme

Свойства компонента могут быть установлены следующим образом:

Компоненты действительно самые простые в использовании в истории, и окончательный эффект, честно говоря, превосходит мои первоначальные мысли, что действительно хорошо.

Недостатки и унаследованные проблемы

  • Ограниченные возможности и энергия, только@primaryColorсоответствующее покрытие
  • По-прежнему требуются другие переопределения: глобальные или внутрикомпонентные переопределения таким образом.
  • Тест эффекта всех компонентов не проводился, возможны отклонения в эффекте некоторых сцен, проблема будет решена со временем.
  • Будет насильно вставлять в проект абзац около 900 строк<style>Этикетка

срочное обновление

Отзыв о расчете цвета

После публикации этой статьи партнер Ant Financial появился в области комментариев и дал плагин для расчета цвета, который у них есть в открытом доступе.Ха-ха, я трудоемкий и трудоемкий, поэтому я изучу его сам. В будущем он может быть заменен на цвет, официально рассчитанный ant-design, чтобы быть ближе к оригинальной версии~**

Некоторые ограничения

Я хочу сказать, что, например, если я установил цвет темы, цвет темы стиля компонента antd действительно был изменен, но если это мой локальный стиль CSS, он не был изменен. Например, у меня есть компонент «Заголовок», начальный цвет фона совпадает с цветом темы, но когда я меняю цвет темы, меняется только цвет темы компонента antd, а цвет темы моего компонента «Заголовок» не изменяется. изменился, поэтому выглядит очень резким~ Вот так:

Для получения более подробной информации, пожалуйста, смотрите комментарии ниже, спасибо @myran за ваши комментарии

Зная этот сценарий, я подумал о решении, динамически добавляя свойство:themeChangeCallback, передайте функцию, параметр - это измененный цвет темы, просто сделайте какой-нибудь контент, соответствующий нашему местному стилю~

 // 主题色修改过后把系统名称的背景色更换 
 themeChangeCallback(color) {
   document.getElementById('sys_name').style.backgroundColor = color;
 }
 ...
 <DynamicAntdTheme
    style={themeStyle}
    placement='bottomLeft'
    themeChangeCallback={this.themeChangeCallback}
 />

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

Проблемы совместимости

Поскольку в обычной разработке отсутствует привычка быть совместимым с IE, этот компонент не поддерживает браузер IE, но некоторые друзья в группе сказали, что их проекты по-прежнему должны быть совместимы с IE.

Последняя версияv0.2.4.

Суммировать

Некоторым людям после прочтения может показаться, что в ней нет технического содержания, и они просто делают много повторяющихся операций CSS, чтобы скрыть имя класса.Честно говоря, я это признаю, но я думаю, что есть известная поговорка:这个世界上本没有路,走的人多了,就变成了路。То же самое и с этим решением, каждый готов заменить большое количество сложных классов в своих проектах, но они не хотят заморачиваться, чтобы получить набор файлов классов общего и общего покрытия, и я просто готов показать вам выход Вот и все. Это не плагин с каким-либо техническим содержанием, я тоже это признаю, ха-ха 😄.

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

Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь с нами вовремя, спасибо 🙏. Не заблудитесь, нажав звездочкуdynamic-antd-theme

Адрес небольшой группы обмена Next.js: