Как создавать темы в vue / webpack с помощью LESS - PullRequest
0 голосов
/ 25 января 2019

Я использую vue с веб-пакетом для записи отдельных файловых компонентов, используя less-loader для анализа <style lang="less"></style> полей в файлах компонентов

Я ищу хороший способ написать темы для сайта. В идеале я хотел бы иметь отдельные theme.less файлы, например, так:

src
|--themes
|  |-- light.less
|  |-- dark.less
|--components
   |-- app.vue
   |-- nav.vue

Где файл theme.less состоит из общих переменных:

@bg:      hsl(251, 44%, 95%);
@sub:     hsl(251, 18%, 81%);
@surface: hsl(251, 18%, 81%);
@text:    hsl(0, 0%, 0%);
@link:    ...

Так что я могу писать стили уровня компонента не зависящим от темы:

<style lang="less">
    #main-content {
        background-color: @bg;
        color: @text;
        border: @primary;
    }
</style>

И сгенерировать CSS, который оборачивает мои предоставленные стили в тематические классы:

.light #main-content {
    background-color: [@bg variable in light.less];
    color: [@text variable in light.less];
    border: [@primary variable in light.less];
}

.dark #main-content {
    background-color: [@bg variable in dark.less];
    color: [@text variable in dark.less];
    border: [@primary variable in dark.less];
}

Чтобы я мог применить класс темы к корневому элементу, например <body class="dark">, и отобразить соответствующие стили.

Каков наилучший способ сделать это?



В настоящее время я реализовал собственное решение, которое использует функцию inject, предоставляемую style-resources-loader:

module.exports = function (source, resources) {
    let newSource = source.trim();

    let themes = resources.map(v => {
        let o = {};
        o.default = v.content.startsWith("/**DEFAULT**/");
        o.name = v.file.split('/').pop().replace(/\.[^/.]+$/, "");
        return o;
    });

    let wrappers = themes.map(v => `
${v.default ? 'body' : '.' + v.name} {
    @import (reference) '../themes/${v.name}.less';
`);

    let compiled = "";
    wrappers.forEach(w => {
        compiled += w + newSource + '\n}\n';
    })

    return compiled
}

Это делается для кода style каждого компонента, он создает несколько блоков тематического класса, таких как

.light { 
    @import (reference) '../themes/light.less';
    [injected source code]
}

.dark { 
    @import (reference) '../themes/dark.less';
    [injected source code]
}

И вставляет код стиля после импорта, позволяя @variable ссылкам в моих компонентах быть привязанными к теме, и выводить css со всеми стилями, обернутыми в несколько классов тем (таким образом, дублируя все стили, которые я пишу для каждой темы) У меня есть в наличии)

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

Спасибо!

1 Ответ

0 голосов
/ 24 мая 2019

У меня точно такая же потребность. Однако я выбрал другой подход, используя Пользовательские свойства CSS (иначе переменные CSS).

Измените ваши LESS-переменные как:

@bg:      var(--bg, lime);
@sub:     var(--sub, lime);
@surface: var(--surface, lime);
@text:    var(--text, lime);
@link:    ...

Затем определите переменные CSS для каждой темы:

:root {
  --bg:      hsl(251, 44%, 95%);
  --sub:     hsl(251, 18%, 81%);
  --surface: hsl(251, 18%, 81%);
  --text:    hsl(0, 0%, 0%);
  --link:    ...
}

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

...