You are browsing Nuxt 2 docs. Go to Nuxt 3 docs, or learn more about Nuxt 2 Long Term Support.
O módulo @nuxtjs/color-mode é uma boa maneira de adicionar o modo escuro ao seu sítio. Porém não apenas faz isto, mudar de escuro para claro mas também para qualquer tema de cor (por exemplo, o modo sépia). Ele até tem deteção automática, é assim que ela escolherá o modo correto dependendo da aparência do seu sistema.
Visualizar a demonstração / Código-fonte
O módulo @nuxtjs/color-mode é uma boa maneira de adicionar o modo escuro ao seu sítio. Porém não apenas faz isto de mudar de escuro para claro mas também para qualquer tema de cor (por exemplo, o modo sépia). Ele até tem auto deteção é assim que ela escolherá o modo correto dependendo da aparência do seu sistema.
O módulo @nuxtjs/color-mode
adiciona uma classe .${color}-mode
ao marcador <html>
. Ele funciona com qualquer algo de Nuxt, seja estático ou servidor e universal ou a renderização no lado do cliente. Ela deteta automaticamente o sistema color-mode, assim você não precisa mudar manualmente a cor.
Ele injeta um auxiliar $colorMode
com:
preference
: O atual modo de cor selecionado (pode ser 'system'
), atualiza-o para mudar a modo de cor preferido do utilizador
value
: Útil para saber qual modo de cor foi detetado quando $colorMode === 'system'
, você não deve atualizá-lo.
unknown
: Útil para saber se, durante a renderização no lado do servidor ou geração estática, nós precisamos renderizar um ocupante (placeholder)
Você pode trabalhar sobre um projeto já criado ou iniciar um completamente novo. Para este exemplo eu criei um novo projeto e adicionei alguns textos ilustrativos ao ficheiro index.vue
na pasta pages
.
<template>
<h1>Testing color mode</h1>
</template>
Antes de tudo você precisa instalar o módulo como uma dependência no seu projeto em Nuxt.
yarn add --dev @nuxtjs/color-mode
npm install --save-dev @nuxtjs/color-mode
Depois você precisa adicionar o módulo à secção buildModules
do seu ficheiro nuxt.config.js
.
nuxt.config.js
você pode criar um no diretório raiz e adicionar o código abaixo.export default {
buildModules: ['@nuxtjs/color-mode']
}
Se você estiver usando uma versão da Nuxt abaixo da 2.9.0
você precisará adicioná-lo à propriedade modules
no lugar da propriedade buildModules
.
yarn nuxt -v
ou npm run nuxt -v
Agora você precisa adicionar alguns estilos às suas classes de modo. Vamos adicionar um ficheiro main.css
à nossa pasta de recursos assets
. Nós utilizaremos variáveis de CSS para definir a cor de raiz a qual será o modo claro e depois definir as cores para modo escuro e sépia. Assim nós podemos adicionar alguns estilos aos marcadores de corpo e ligação (body
e a
).
:root {
--color: #243746;
--color-primary: #158876;
--color-secondary: #0e2233;
--bg: #f3f5f4;
--bg-secondary: #fff;
--border-color: #ddd;
}
.dark-mode {
--color: #ebf4f1;
--color-primary: #41b38a;
--color-secondary: #fdf9f3;
--bg: #091a28;
--bg-secondary: #071521;
--border-color: #0d2538;
}
.sepia-mode {
--color: #433422;
--color-secondary: #504231;
--bg: #f1e7d0;
--bg-secondary: #eae0c9;
--border-color: #ded0bf;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
background-color: var(--bg);
color: var(--color);
transition: background-color 0.3s;
}
a {
color: var(--color-primary);
}
No sentido de usar este ficheiro de CSS em nossa aplicação nós precisamos registá-lo. Nós fazemos isto ao adicionar uma propriedade css
ao nosso ficheiro de configuração e adicionando o ficheiro de css que já temos criado.
css: ['@/assets/main.css']
Agora se você iniciar o seu sítio com npm run dev
ou npx nuxt dev
você deve ver o modo escuro se o seu sistema já estiver definido para o modo escuro e se você inspecionar o código verá a classe adicionada ao seu marcador de html.
<html class="dark-mode">
// you might have light-mode here
</html>
Usando as ferramentas de desenvolvedor mude o modo para o modo sépia e modo claro para ver os efeitos.
<html class="sepia-mode">
<!-- ou -->
<html class="light-mode">
<!-- ou modo escoro se você já estiver vendo o claro -->
</html>
</html>
Você também pode mudar a cor na consola ao digitar:
$nuxt.$colorMode.preference = 'sepia'
Obviamente mudar o modo nas ferramentas do desenvolvedor não é o que nós queremos então vamos criar um interruptor de modo de cor, assim os nossos utilizadores podem rapidamente mudar de uma cor para uma outra.
Vamos criar um componente chamado ColorModePicker
e nós podemos adicionar uma lista de cores. Por agora nós podemos apenas imprimir a cor a partir do nosso v-for
.
<template>
<div>
<ul>
<li v-for="color of colors" :key="color">
{{color}}
</li>
</ul>
</div>
</template>
E a nossa propriedade de dados nos deixa retornar um arranjo de cores para cada modo.
<script>
export default {
data() {
return {
colors: ['system', 'light', 'dark', 'sepia']
}
}
}
</script>
Vamos importar o nosso componente para dentro da nossa página index.vue
, assim podemos ver o que está acontecendo.
<template>
<ColorModePicker />
</template>
<script>
import ColorModePicker from '@/components/ColorModePicker'
export default {
components: {
ColorModePicker
}
}
</script>
E no nosso navegador por baixo de http://localhost:3000
você verá a nossa lista de cores.
Depois em nosso modelo de marcação nós podemos adicionar um evento de clique que tornará o $colorMode.preference
igual a cor que vem dos nossos dados.
Nós pode usar o nosso auxiliar $colorMode
que nós recebemos com o módulo color-mode
. Quando o utilizador clicar o $colorMode.preference
será definido para a cor vindo dos nossos dados.
<li
v-for="color of colors"
:key="color"
@click="$colorMode.preference = color"
></li>
Isto é de fato tudo o que você precisa no sentido de isto funcionar. Se vocÊ consultar no seu navegador você verá que ao clicar em quaisquer uma das cores o fundo está mudando. Ele provavelmente não terá um cursor de ponteiro, então se você pensar que isto não funciona, ele funciona, você apenas está acostumado a ver o cursor.
E se nós consultar no navegador nós podemos ver que ele funciona mas está muito feito. Vamos arrumá-lo um pouco.
Vamos adicionar alguns ícones. Você pode copiar os ícones daqui e colocá-los na sua pasta de recursos assets
em uma nova pasta chamada icons
.
Nós usaremos os nossos ícones como um componente e no sentido de fazer isto nós usaremos o módulo @nuxtjs/svg
que permite-te importar os ficheiros .svg
de várias maneiras dependendo consulta de recurso que você fornecer.
Primeiro você precisará instalá-lo.
yarn add --dev @nuxtjs/svg
# OU npm install --save-dev @nuxtjs/svg
Depois nós precisamos adicioná-lo ao seu nuxt.config.js
buildModules: ['@nuxtjs/svg', '@nuxtjs/color-mode']
Nós agora podemos importas estes ícones em svg como componentes usando a pergunta ?inline
, assim eles são importados como SVGs em linha.
<script>
import IconSystem from '@/assets/icons/system.svg?inline'
import IconLight from '@/assets/icons/light.svg?inline'
import IconDark from '@/assets/icons/dark.svg?inline'
import IconSepia from '@/assets/icons/sepia.svg?inline'
export default {
components: {
IconSystem,
IconLight,
IconDark,
IconSepia
},
// ... a propriedade de dados (data) estará aqui
</script>
Agora nós podemos usar um componente dinâmico o qual verificará qual ícone adicionar dependendo das cores no nosso arranjo de dados. Vamos substituir o texto {{color}}
por este novo componente dentro da nossa <li>
.
<component :is="`icon-${color}`" />
Vamos mover o nosso evento de clique do nossa <li>
para o nosso componente de ícone.
<component :is="`icon-${color}`" @click="$colorMode.preference = color" />
E vamos adicionar alguns estilos, assim nós pode ver os nossos ícones. Nós usaremos estilização isolada (scoped) e usaremos a classe feather
. Se você olhar para dentro do seus ficheiros em svg você verá que os nossos ficheiros em SVG tem a classe feather
, assim nós podemos usar esta classe para o estilizar. Nós também adicionaremos uma classe preferida (preferred) e selecionada (selected), assim nós sabemos qual delas tem sido selecionada e qual é a preferida.
<style scoped>
.feather {
position: relative;
top: 0px;
cursor: pointer;
padding: 7px;
background-color: var(--bg-secondary);
border: 2px solid var(--border-color);
margin: 0;
border-radius: 5px;
transition: all 0.1s ease;
}
.feather:hover {
top: -3px;
}
.feather.preferred {
border-color: var(--color-primary);
top: -3px;
}
.feather.selected {
color: var(--color-primary);
}
</style>
Você não verá muita diferença de imediato exceto que o ícones parecem um pouco melhor mas agora nós precisamos mostrar uma classe diferente para o nosso ícone preferido o qual vem do nosso sistema de preferência e aquela para o nosso ícone selecionado o qual é para quando nós usarmos o evento de clique para mudar a cor.
Para fazer isso nós podemos criar um método que retornará a classe que nós queremos. Nós podemos chamar o nosso método de getClasses
e passar a cor como o parâmetro. As duas classes que nós queremos retornar são preferred
e selected
. A cor preferida (preferred
) deve ser igual ao $colorMode.preference
e a cor selecionada (selected
) deve ser igual ao $colorMode.value
. Se o colorMode
for desconhecido nós podemos retornar um objeto vazio.
data () {
return {
colors: ['system', 'light', 'dark', 'sepia']
}
},
methods: {
getClasses (color) {
// Não definir classes na renderização no lado do servidor quando a preferência (`preference`) for sistema (`system`) (porque nós não sabemos a preferência até o lado do cliente)
if (this.$colorMode.unknown) {
return {}
}
return {
preferred: color === this.$colorMode.preference,
selected: color === this.$colorMode.value
}
}
}
Agora nós podemos adicionar esta classe ao nosso componente de ícone. A classe chamará o método getClasses
passando a cor que nós recebemos quando nós usamos o evento de clique.
<component
:is="`icon-${color}`"
@click="$colorMode.preference = color"
:class="getClasses(color)"
/>
E agora você verá no navegador que as cores que estão sendo aplicadas como nós queríamos. Mas não está muito claro sobre o que está acontecendo quando clicamos no sistema de ícone.
Vamos adicionar algo que ajude o utilizador a compreendê-lo.
Se você está fazendo a renderização no lado do servidor (nuxt start
ou nuxt generate
) e se $colorMode.preference
está definido para 'system'
, usar o $coloMode
em seu modelo de marcação de Vue levará um clarão. Isto é por causa do fato de que nós não podemos saber as preferências do utilizador quando estivermos pré-renderizando a página visto que elas são detetadas no lado do cliente.
Para evitar o clarão, nós temos que guardar qualquer caminho de renderização que dependa de $colorMode
com o $colorMode.unknown
para renderizar o segurador de lugar (placeholder) ou usar o nosso componente <ColorScheme>
.
Vamos criar um componente ColorScheme
dentro do nosso elemento <ul>
com um segurador de lugar e um marcador de span
. Dentro dele nós podemos adicionar algum texto e exibir o $colorMode.preference
que nós recebemos do módulo color-mode
.
<ColorScheme placeholder="..." tag="span">
Color mode: <b>{{ $colorMode.preference }}</b>
</ColorScheme>
Agora você verá no navegador que se você mudar o ícone, o texto aparecerá o que corresponde ao ícone clicado.
Nós podemos melhorar isto ainda mais ao ver quando a preferência é o sistema e adicionar uma outra mensagem que exibe qual valor foi detetado.
<ColorScheme placeholder="..." tag="span">
Color mode: <b>{{ $colorMode.preference }}</b>
<span v-if="$colorMode.preference === 'system'"
>(<i>{{ $colorMode.value }}</i> mode detected)</span
>
</ColorScheme>
Se você testar isto no navegador, você verá que está parecendo-se muito bem e nós estamos quase lá.
Agora nós apenas temos que arrumar um pouco os estilos. Vamos remover os pontos da <ul>
e adicionar algum espaçamento e algum estilo ao nosso marcador <p>
.
ul {
list-style: none;
padding: 0;
margin: 0;
}
ul li {
display: inline-block;
padding: 5px;
}
p {
margin: 0;
padding-top: 5px;
padding-bottom: 20px;
}
E no sentido de centralizá-lo, nós podemos envolver o nosso componente ColorModePicker
em uma div
com a classe de container
.
<div class="container">
<ColorModePicker />
</div>
E adicionar os estilos à classe container
nos nossos estilos.
<style scoped>
.container {
text-align: center;
padding: 50px;
}
</style>
E aí você tem o seu componente color-mode
bonito e completamente funcional. Sinta livre para divertir-se um pouco mais ao mudar os ícones ou adicionar mais cores ou modificar o esquema de cor. Divirta-se.
color-mode
com o Tailwind, consulte este artigo .