Adjust the element colors within a Vue loop with dynamic changes

Hey there! I'm currently working on achieving a unique design inspiration that involves colorful badges grouped together. Here's a visual reference: https://i.sstatic.net/5LDBh.png

In the image, you can see these badges grouped in pairs, but they can actually be in sets of 4 or even 5.

My goal is to dynamically change both the background and text colors of each badge within every group programmatically.

I've experimented with numerous approaches, but none have quite hit the mark yet. At best, I've only been able to adjust the color of the first badge.

Here's a snippet from my page layout:

<template>
  <div class="w-full flex flex-col px-6">
    ...
    ... (rest of the template)
    ...
  </div>
</template>

<script>
import { mapState } from 'vuex';
...
... (remaining script content)
...
</script>

This component houses the mentioned badge:

<template>
  ...
  ... (component structure)
  ...
</template>

<script>
import { mapState } from 'vuex';

export default {
  name: 'type',
  props: ['name', 'bg-color', 'text-color'],
  computed: {
    ...mapState({
        colours: state => state.schedule.colours
    }),
  }
}
</script>

Furthermore, here's an overview of my store file:

export const state = () => ({
    ...
    ... (store state details)
    ...
});

export const mutations = {
    ...
    ... (mutations description)
    ...
}

export const actions = {
    ...
    ... (actions summary)
    ...
}

Ultimately, my objective is to randomly assign distinctive background colors to each individual badge within the groups, ensuring optimal visibility of text based on the color contrast. The challenge lies in applying this logic seamlessly across all badges without any repetition of colors.

If anyone has insights into how I can achieve this fluid color assignment for all badges within their respective groups, your guidance would be immensely appreciated! Thank you.

Answer №1

Here is a straightforward solution that does not require Vuex. It should work fine if you feel the need for something global.

<template>
  <div>
    <div
      v-for="(button, index) in numberOfIterations"
      :key="button"
      :class="[arrayOfColours[findRandomInRange()]]"
    >
      div #{{ index }}
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arrayOfColours: ['red', 'blue', 'orange'],
      numberOfIterations: 6,
    }
  },
  methods: {
    findRandomInRange() {
      return Math.floor(Math.random() * this.numberOfIterations) % this.arrayOfColours.length
    },
  },
}
</script>

<style>
.red {
  background-color: red;
}
.blue {
  background-color: blue;
}
.orange {
  background-color: orange;
}
</style>

Explanation:

  • numberOfIterations is simply used to create a basic loop
  • % this.arrayOfColours.length is used to ensure colors stay within bounds. For example, with only 3 colors and 6 iterations, trying to get the 5th color would be problematic
  • findRandomInRange() is called during rendering to apply random coloring
  • A better value than :key could be utilized here
  • In this example, colors are shuffled each time they're rendered

Hopefully, the rest is self-explanatory.

See how it looks https://i.sstatic.net/edoD4.png


EDIT: If you want unique colors but still random, the code can be even more concise.

<template>
  <div>
    <div v-for="(button, index) in arrayOfColours" :key="button" :class="[arrayOfColours[index]]">
      div #{{ index }}
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arrayOfColours: ['red', 'blue', 'orange'],
    }
  },
  created() {
    this.shuffle() // shuffle before mounting to DOM
  },
  methods: {
    shuffle() {
      this.arrayOfColours.sort(() => Math.random() - 0.5)
    },
  },
}
</script>

Answer №2

Your code is almost there, but the issue lies in the class binding:

<div :class="{bgColor: true, textColor}"> ❌

The current binding assigns two classes, "bgColor" and "textColor," to the div. If you want these values to be class names instead, you should bind an array of those props:

<div :class="[bgColor, textColor]">

If these class names match existing styles, the background and text color will update accordingly.

To randomize badge colors, you can shuffle a copy of the state.schedule.colours array within a computed property:

// https://stackoverflow.com/a/2450976/6277151
function shuffleArray(array) {
  if (!array || array.length <= 1) return array;
  array = array.slice();
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    const temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }
  return array;
}

export default {
  computed: {
    ...mapState({
      colours: state => shuffleArray(state.schedule.colours)
    }),
  }
}

Check out this demo for reference.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Alter the background shade of an item as it is added or removed from a multi-select list and transferred to another list

Is there a way to visually represent the movement of items between two multi-select lists? I have one list on the right and one on the left, and when objects move from right to left, I want them to have a red background (indicating removal) and if they mov ...

Vue component prop values are not properly recognized by Typescript

Below is a Vue component I have created for a generic sidebar that can be used multiple times with different data: <template> <div> <h5>{{ title }}</h5> <div v-for="prop of data" :key="prop.id"> ...

The LESS file could not be located. Attempted to find -

My directory structure is as follows: C:. └───static ├───custom_stuff │ presets.css │ presets.less │ └───index index.less However, I'm encountering an issue where index.less c ...

Enhance the responsiveness of a ReactJS landing page

We have developed a large React application without relying on any existing UI framework. All of our UI components have been custom-built. Now, we are looking to make the landing page section responsive within the application, which will require the imple ...

Can you explain the significance behind this unorthodox CSS code?

Assisting a customer in updating their Shopify theme. The previous designer used an unconventional method to establish the grid system. I require assistance in decoding the code. I came across an old article on this topic but still couldn't grasp it. ...

How can you utilize an Express server to redirect a NuxtJs application?

My NuxtJs application is set up with an Express server using npx create-nuxt-app <project-name>. The configuration allows for server-side rendering. The Express server has access to NuxtJs middleware, as shown below: app.use(nuxt.render) I have cr ...

What is the best way to swap out an array with a new array in Vue?

Every 10 seconds, I am querying my database for the latest fire calls. When I use app.events = data.calls, the data does not refresh. I initialize the data with the same function that is called every 10 seconds and I can see the table. How do I replace a ...

Something is off with the CSS height property

I am facing an issue with setting the height of a div inside another div. To better illustrate my problem, here is the code snippet: .prodContent1 { position: absolute; background-color: #e1e1e1; border: 1px solid #ddd; width: 100%; box-sizi ...

What are some effective methods for testing web applications on mobile devices?

While I may not have the funds to purchase mobile phones and iPhones, I am eager to ensure my web applications can be accessed on mobile devices. Are there any software solutions available to simulate these devices, or what steps should I take? ...

Using namespaces in Rails to encapsulate CSS styles

Is there a way to add namespaces to CSS within a Rails project? I have two pre-defined CSS files and two application layouts. I want the first layout to use one CSS file, and the second layout to use the other. However, both CSS files have styles for the ...

Display a basic Google map in Nuxt.js

I've been able to successfully implement this feature in another project, so I'm quite puzzled as to why I'm seeing an empty div instead of a map rendering here. The map should be displayed in this section: <template> <div class ...

Having difficulty formatting text alignment using CSS

Is there a way to maintain the alignment of text in the output of the 'About' section even when the content changes dynamically? I want the new line to appear just below 'Lorem', but currently, it shifts below the colon(:). Since the le ...

The font appears bolder in Chrome once the CSS animation has finished

My CSS animation is causing some unexpected behavior on page load. Once the animation completes, the text suddenly appears thicker than intended, especially when it's a specific shade of red. Curiously, this strange "popping" effect only occurs with ...

Vue and Vite: Leveraging Static SVG Assets

I am currently working on my Vue Vite application and I am facing an issue with using an SVG file as the src attribute in an HTML element. <img class="..." src="/src/assets/images/bg/main-banner.svg" alt="Background"> D ...

Getting elements to vertically align in the center and have matching heights using Bootstrap

Does anyone have experience with vertical aligning in Bootstrap using flex box classes like align-items-center? I'm struggling to vertically center the text content in the boxes of the codepen provided below while ensuring each box matches the height ...

How can I easily add both horizontal and vertical arrows to components in React?

Creating a horizontal line is as simple as using the following code: <hr style={{ width: "80%", border: "1px solid black" }} /> You can customize the width, length, and other properties as needed. If you want to display an arrow ...

Attempting to remove options in a Multiple Choice scenario by selecting the X icon beside each one

I'm working on a multiple choice quiz and I'd like to add a button or icon resembling X in front of each option (even in front of the radio button), so that when I click on it, only that specific option is deleted. How can I achieve this? For in ...

"Passing data from a child component to a parent component using Vue's emit

offspring template: ` <li v-for="option in listaOptiuni" :key="option.id"> <input @change="updateSelectAllToateOptiunile(); sendListaToateOptiunile()" v-model="listaToateOptiunile" :value="o ...

Type of element returned

Is there a way to retrieve the element type? I'm interested in applying the style of a class to HTML5 elements without using the class attribute. <!DOCTYPE> <html> <head> <title>My page</title> </head& ...

The button is not being vertically centered when using the boostrap pull-right class

---------------------------------------------------------------- | Title | | Button | --> (using .pull-right) the button is not aligned vertically ------------------------------------------------------------- ...