WoJ
WoJ

Reputation: 30054

Is it possible to point to a class?

I have a Vue application (a all-encompassing element with with several child components) to which I would like to add a night mode. I would like this night mode to be managed centrally, where the relevant styling would be applied to the elements which need to switch to night/day mode.

If I have an element (it is in the DOM as part of a component having been rendered, so not directly available to the parent component and therefore not bindable via v-bind)

<div class="night-day">hello</div>

and two classes

.night {
  background-color: black;
  color: red
}

.day {
  background-color: white;
  color: black
}  

is it possible to have night-day pointing to either day or night (depending on some condition)?

Upvotes: 1

Views: 85

Answers (4)

mava
mava

Reputation: 2854

you could use v-bind:class (Class binding) from vue for this. Like:

 <div class="static" v-bind:class="{ night: isNight, day: !isNight }"></div>

Upvotes: 1

tony19
tony19

Reputation: 138696

Using event bus

You could use a class binding to bind a CSS class to a property, controlled by an event handler.

// MyComponent.vue
<template>
  <div class="daynightdemo" :class="{ night: isNight }">
    ...
  </div>
</template>

<script>
import { eventBus } from '@/eventBus'

export default {
  data() {
    return {
      isNight: false
    };
  },
  mounted() {
    this.setNightDay = value => {
      this.isNight = value === "night";
    };
    eventBus.$on("nightDay", this.setNightDay);
  },
  beforeDestroy() {
    eventBus.$off("nightDay", this.setNightDay);
  }
}
</script>

You mentioned the event bus being periodically called from setInterval. In this example, the call would look like something like this:

// App.vue
export default {
  mounted() {
    let isNight = true;
    setInterval(() => {
      eventBus.$emit("nightDay", isNight ? "night" : "day");
      isNight = !isNight;
    }, LONG_INTERVAL);
  }
};

demo with event bus

Using Vuex

Using Vuex, the boilerplate would be somewhat simplified, obviating the need for event-callback registration and unregistration:

// MyComponent.vue
<template>
  <div class="daynightdemo" :class="{ night: $store.state.isNight }">
    <h1>isNight: {{ $store.state.isNight }}</h1>
  </div>
</template>

// App.vue
export default {
  mounted() {
    setInterval(() => {
      this.$store.state.isNight = !this.$store.state.isNight;
    }, 2000);
  }
}

demo with Vuex

Upvotes: 1

Temani Afif
Temani Afif

Reputation: 274086

You can consider the use of CSS variables that you change within your JS code (setinterval). Basically you will have something like this:

<div class="night-day">hello</div>


.night-day {
  background-color: var(--bc,black);
  color: var(--c,red)
}

And within your JS you will have something like this:

var bc= ["black", "white"]
var c= ["red", "black"]

....
document.querySelector('.night-day').style.setProperty("--bc", bc[i]);
document.querySelector('.night-day').style.setProperty("--c",  c[i]);

...

Where i is an index that you can change based on your conditions:

Upvotes: 1

Kevin Pastor
Kevin Pastor

Reputation: 801

I think the best approach for solving the multiple themes problem would be to have a theme class modifier on the body tag and in your CSS, modify your subelements accordingly. Here's an example to clarify things up.

<body class="dark-theme">
    <div class="container">
        Content...
    </div>
</body>

.container {
  background-color: white;
  color: black
}

.dark-theme .container {
  background-color: black;
  color: red
}

Toggling .dark-theme on the body, in this case, would switch between the default theme and the dark theme.

Upvotes: 1

Related Questions