Different ways to customize specific calendar entries using v-bind: class

In the afternoon, I created a custom calendar with styled elements. My goal is to highlight the last days of the previous month and the first days of the next month in a different color, while always displaying the current day in blue. I aim to achieve this using v-bind: class.

Check out my code on GitHub

View screenshot of the calendar

<template>
  <div class="all">
    <div class="allсalendar">
      <div class="pagination">
        <div @click="prevPage"
              ><</div> 
        <p>{{ nameOfOneMonth }} {{ year }}</p>
        <div @click="nextPage"
              >></div> 
      </div>

      <div class="calendar">
        <div class="d_nameOfDays">
          <li v-for="day in nameOfDays" class="nameOfDays">{{ day }}</li>
        </div>

        <div v-for="(week, i) in getCalendar" class="d_day">
          <div v-for="day in week" class="day">{{ day }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>

export default {
  data(){
    return{
      currentPage: 0,
      namesOfMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
      nameOfOneMonth: '',
      nameOfDays: ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'],
      date: new Date(),
      year: ''
    }
  },
  computed: {
    getCalendar(){
      return this.buildCalendar();
    }
  },
  mounted(){
    this.year = this.date.getFullYear();
    this.currentPage = this.date.getMonth();
    this.nameOfOneMonth = this.namesOfMonths[this.currentPage];
  },
  methods: {
    prevPage(){
      if (this.currentPage === 0) {
        this.currentPage = 12;
        this.year--;
      }
      this.currentPage--;
      this.nameOfOneMonth = this.namesOfMonths[this.currentPage];
    },
    nextPage(){
      if (this.currentPage === 11) {
        this.currentPage = -1;
        this.year++;
      }
      this.currentPage++;
      this.nameOfOneMonth = this.namesOfMonths[this.currentPage];
    },
    getYear(){
      this.year = this.date.getFullYear();
    },
    getLastDayOfMonth(month) { // Find the last day of the month
      let dateDaysInMonth = new Date(this.year, month + 1, 0);
      return dateDaysInMonth.getDate();
    },
    getNumberOfFirstDayInMonth(month){ // Find the number of the first day in the month
      let dateFirstDayInMonth = new Date(this.year, month, 1);
      return dateFirstDayInMonth.getDay();
    },
    buildCalendar(){
      let massOfMonth = [];
      for (let months = 0; months < 12; months++){
        massOfMonth.push(months);
        massOfMonth[months] = [];
        for ( let daysInMonth = 1; daysInMonth <= this.getLastDayOfMonth(months); daysInMonth++){
          massOfMonth[months].push(daysInMonth);
        }
        // Fill the beginning of each month with numbers from the previous month
        if(this.getNumberOfFirstDayInMonth(months) > 0){
          let t = this.getLastDayOfMonth(months-1) + 1;
          for(let b = 0; b <= this.getNumberOfFirstDayInMonth(months) - 2; b++){
            t--;
            massOfMonth[months].unshift(t)
          }
        }else if(this.getNumberOfFirstDayInMonth(months) === 0){
          let t = this.getLastDayOfMonth(months-1) + 1;
          for(let nulldays = 0; nulldays <= 5; nulldays++){
            t--;
            massOfMonth[months].unshift(t);
          }
        }
        // Fill the end of each month with numbers from the future month
        if(this.getNumberOfFirstDayInMonth(months + 1) > 1){
          let t = 0;
          for(let q = this.getNumberOfFirstDayInMonth(months + 1); q <= 7; q++){
            t++;
            massOfMonth[months].push(t);
          }
        } else if(this.getNumberOfFirstDayInMonth(months + 1) === 0){
          massOfMonth[months].push(1);
        }
      }

      // Split the large month array into smaller arrays that have 7 elements each
      var longArray = massOfMonth[this.currentPage];
      var size = 7;

      var newArray = new Array(Math.ceil(longArray.length / size)).fill("")
          .map(function() { 
            return this.splice(0, size) 
          }, longArray.slice());
       
        return newArray; // Return the constructed calendar
    }
  }
};
</script>

<style>
  body{
    background-color: #FAFAFA;
  }
  .allсalendar{
    background-color: white;
    margin-left: 30px;
    margin-right: 80%
  }
  .pagination{
    justify-content: space-between;
  }
  .pagination, .nameOfDays{
    display: flex;
  }
  .nameOfDays{
    font-size: 20px;
  }
  .pagination div{
    width: 30px;
    height: 30px;
    padding-top: 8px;
    margin-bottom: -5px;
    text-align: center;
    font-size: 20px;
    font-weight: bold;
    cursor: pointer;
  }
  .pagination div:active{
    color: #9D9D9D;
  }
  .pagination div:hover{
    color: white;
    background-color: #DEDEDE;
  }
  .pagination p{
    margin: 10px auto 5px auto;
    text-align: center;
    font-weight: bold;
    font-size: 18px;
  }
  .d_nameOfDays{
    margin: 5px auto 5px auto;
    padding-left: 10px;
    background-color: #DEDEDE;

  }
  .nameOfDays, .day{
    list-style-type: none;
    text-align: center;
    cursor: pointer;
  }
  .d_day, .d_nameOfDays{
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
  }
  .day{
    font-size: 18px;
  }
  .day:hover {
    background: #16B9DE;
    color: white;
    border-radius: 10%;

  }
  .grey{
    color: red;
  }
</style>

Answer №1

I successfully achieved it by making 2 modifications:

Firstly, I included the v-bind:class in your HTML code to dynamically add a class based on a method of the component

<div v-for="(week, i) in getCalendar" class="d_day">
        <div v-for="day in week" class="day" v-bind:class="{ grey: isAnotherMonth(i, day) }">{{ day }}</div>
    </div>

Next, I created a method with a condition where if it's the first week displayed and the day number is greater than 15, it indicates the end of the previous month. The same logic applies for the last week (I chose 15 as it represents half of a month, but any value between 8 and 20 could work)

isAnotherMonth(weekIndex, dayNumber) {
      return weekIndex === 0 && dayNumber > 15 || weekIndex === 4 && dayNumber < 15
    },

Responding to requests for a more readable version using if statements:

isAnotherMonth(weekIndex, dayNumber) {
      if(weekIndex === 0 && dayNumber > 15) {
        // First week and number > 15
        return true
      }
      if (weekIndex === 4 && dayNumber < 15) {
        // Last week and number < 15
        return true
      }
      // Day belongs to current month
      return false
    },

Lastly, here are some code snippets which may have issues with your CSS but should still be comprehensible

Vue.component("test-calendar", {
  template: `
  <div class="all">
    <div class="allсalendar">
      <div class="pagination">
        <div @click="prevPage"
              ><</div> 
        <p>{{ nameOfOneMonth }} {{ year }}</p>
        <div @click="nextPage"
              >></div> 
      </div>

      <div class="calendar">
        <div class="d_nameOfDays">
          <li v-for="day in nameOfDays" class="nameOfDays">{{ day }}</li>
        </div>

        <div v-for="(week, i) in getCalendar" class="d_day">
          <div v-for="day in week" class="day" v-bind:class="{ grey: isAnotherMonth(i, day) }">{{ day }}</div>
        </div>
      </div>
    </div>
  </div>`,
  data(){
    return{
      currentPage: 0,
      namesOfMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
      nameOfOneMonth: '',
      nameOfDays: ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'],
      date: new Date(),
      year: ''
    }
  },
  computed: {
    getCalendar(){
      return this.buildCalendar();
    }
  },
  mounted(){
    this.year = this.date.getFullYear();
    this.currentPage = this.date.getMonth();
    this.nameOfOneMonth = this.namesOfMonths[this.currentPage];
  },
  methods: {
    isAnotherMonth(weekIndex, dayNumber) {
      return weekIndex === 0 && dayNumber > 15 || weekIndex === 4 && dayNumber < 15
    },
    prevPage(){
      if (this.currentPage === 0) {
        this.currentPage = 12;
        this.year--;
      }
      this.currentPage--;
      this.nameOfOneMonth = this.namesOfMonths[this.currentPage];
    },
    nextPage(){
      if (this.currentPage === 11) {
        this.currentPage = -1;
        this.year++;
      }
      this.currentPage++;
      this.nameOfOneMonth = this.namesOfMonths[this.currentPage];
    },
    getYear(){
      this.year = this.date.getFullYear();
    },
    getLastDayOfMonth(month) { 
      let dateDaysInMonth = new Date(this.year, month + 1, 0);
      return dateDaysInMonth.getDate();
    },
    getNumberOfFirstDayInMonth(month){ 
      let dateFirstDayInMonth = new Date(this.year, month, 1);
      return dateFirstDayInMonth.getDay();
    },
    buildCalendar(){
      let massOfMonth = [];
      for (let months = 0; months < 12; months++){
        massOfMonth.push(months);
        massOfMonth[months] = [];
        for ( let daysInMonth = 1; daysInMonth <= this.getLastDayOfMonth(months); daysInMonth++){
          massOfMonth[months].push(daysInMonth);
        }
        
        if(this.getNumberOfFirstDayInMonth(months) > 0){
          let t = this.getLastDayOfMonth(months-1) + 1;
          for(let b = 0; b <= this.getNumberOfFirstDayInMonth(months) - 2; b++){
            t--;
            massOfMonth[months].unshift(t)
          }
        } else if(this.getNumberOfFirstDayInMonth(months) === 0){
          let t = this.getLastDayOfMonth(months-1) + 1;
          for(let nulldays = 0; nulldays <= 5; nulldays++){
            t--;
            massOfMonth[months].unshift(t);
          }
        }
        
        if(this.getNumberOfFirstDayInMonth(months + 1) > 1){
          let t = 0;
          for(let q = this.getNumberOfFirstDayInMonth(months + 1); q <= 7; q++){
            t++;
            massOfMonth[months].push(t);
          }
        } else if(this.getNumberOfFirstDayInMonth(months + 1) === 0){
          massOfMonth[months].push(1);
        }
      }

      var longArray = massOfMonth[this.currentPage];
      var size = 7;

      var newArray = new Array(Math.ceil(longArray.length / size)).fill("")
          .map(function() { 
            return this.splice(0, size) 
          }, longArray.slice());
         
        return newArray; 
    }
  }
});

new Vue({el:"#vue"})
  body{
    background-color: #FAFAFA;
  }
  .allсalendar{
    background-color: white;
    margin-left: 30px;
    margin-right: 80%
  }
  .pagination{
    justify-content: space-between;
  }
  .pagination, .nameOfDays{
    display: flex;
  }
  .nameOfDays{
    font-size: 20px;
  }
  .pagination div{
    width: 30px;
    height: 30px;
    padding-top: 8px;
    margin-bottom: -5px;
    text-align: center;
    font-size: 20px;
    font-weight: bold;
    cursor: pointer;
  }
  .pagination div:active{
    color: #9D9D9D;
  }
  .pagination div:hover{
    color: white;
    background-color: #DEDEDE;
  }
  .pagination p{
    margin: 10px auto 5px auto;
    text-align: center;
    font-weight: bold;
    font-size: 18px;
  }
  .d_nameOfDays{
    margin: 5px auto 5px auto;
    padding-left: 10px;
    background-color: #DEDEDE;

  }
  .nameOfDays, .day{
    list-style-type: none;
    text-align: center;
    cursor: pointer;
  }
  .d_day, .d_nameOfDays{
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
  }
  .day{
    font-size: 18px;
  }
  .day:hover {
    background: #16B9DE;
    color: white;
    border-radius: 10%;

  }
  .grey{
    color: red;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="vue">
<test-calendar></test-calendar>
</div>

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

I'm struggling to adjust the height of a div based on whether a list item within it contains a nested unordered

I have been working on a horizontal menu that is functioning well for me. However, according to the design requirements, I need to adjust the height of <div id="nav-subMenu"></div> if the main/parent menu li does not have any submenus or ul. Th ...

Error encountered when attempting to use regex in javascript with an invalid group

After coming across a regex that checks for multiple types of email address inputs, I encountered an issue while trying to use it in JavaScript. The error message "Uncaught SyntaxError: Invalid regular expression" kept popping up along with details about i ...

What is the best way to transfer information between two components when working with an edit form?

Presently, I am utilizing a modal material dialog window that prompts the user to input a number and then press search. Upon searching, it retrieves data from an API call and receives a response object. My goal is to utilize this response object to populat ...

Using Reactjs to dynamically create a table from an array

I've recently started using React JS and encountered a challenge with the following JavaScript array: (7) [Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4)] 0: (4) ["050222222", "field", "field", " ...

Some CSS features might not work properly when using Vuetify alongside Vue.js and Webpack

I believe the issue may stem from my inability to correctly import the JS file for Vuetify, but I haven't been able to pinpoint any errors. It seems that certain CSS functionalities of Vuetify, like list highlight events, are not working in my applica ...

The function sendKeys with protractor's Key.Tab input is failing to function

Currently, I am using Protractor along with JavaScript. The issue I'm facing is that the SendKeys(protractor.Key.TAB) function does not seem to be tabbing out from the input field. Please find below the HTML tag for the input field: <td> < ...

Having trouble with submitting the code - need help resolving the issue

I'm facing an issue with my submit cancel code. The JavaScript code I implemented for preventing the submission function on my page isn't working as expected. While it does work to a certain extent, it's not fully functional. I am seeking a ...

Codeigniter AJAX request not populating data

While I'm still learning to use Codeigniter, I have been working with it for some time now. My current issue involves creating an SQL query to search for books in the database, but the AJAX request always comes back empty. I did some debugging by ec ...

Conceal div element when clicked on the client side

Attempting to make this particular div disappear, but it is not behaving as I anticipated. Can someone point out where my mistake lies? The div is not disappearing. JavaScript: <script type="text/javascript> function Show_Hide_Display() { va ...

What is the best way to align the logo image in the center of the header vertically?

I am trying to vertically center my logo, but I have not been successful with using margin: auto or margin: center. Here is what I have tried so far: ・text-align: center; ・margin: auto; ・margin: center: ・navbar-brand-center The logo currently app ...

Discovering all input elements by utilizing nextAll in jQuery

Here is the HTML structure: <div class="field phone"> <input type="text" maxlength="3" /> </div> <div class="field phone number1"> <input type="text" maxlength="3" /> & ...

Ways to display an HTML code by utilizing the onclick() function through PHP?

I have a button that looks like this: <input type="submit" name="submit5" class="btn" value="Add Date" onclick="create_date_field()" /> Every time the button is clicked, I want to append the following code inside the <tr> tags. It should be po ...

Please ensure that only plain objects and a select few built-ins are passed from Server Components to Client Components. It is important to note that classes and null prototypes are not compatible for

Using React Query, I am able to fetch JSON files from an external API. Below is the fetch hook: import { QueryClient, QueryKey, useQuery } from "@tanstack/react-query"; let Tmdb: string; if (typeof process.env.NEXT_PUBLIC_TMDBURL === "st ...

Looking for a way to locate the previous sorted element in jQuery?

<div id="con" > <p class="bb">1</p> <p class="aa">2</p> <p class="aa">3</p> <p class="bb">4</p> /*----- i need to reference this */ <p class="aa">5</p> <p class="a ...

Using Three JS OrbitControls within a JQuery Draggable interface

My challenge involves using a canvas containing cubes inside a draggable element. I am trying to rotate the camera using OrbitControls, but I am facing an issue where instead of just rotating the cubes, it also starts dragging on left click (I would like t ...

After the ReactJS onload event, CSS animations malfunction

When I click on a Card component within the MoviesList component, it redirects me to the SingleMoviePage component. The genres, starring, release date, production, and stars sections all have animations that slide from left to right. Initially, these anima ...

Tips for increasing efficiency in Javascript development by leveraging the power of the computer to automate tasks and minimize manual work

When working with JavaScript, what techniques can be used to develop and test efficiently and accurately while focusing on algorithms rather than mechanics? Are there any useful tools that can be utilized in batch or command line mode (outside of an integr ...

Why is the image auto-swapping script failing to display images frequently?

I have a script that is currently running to rotate between two different logos on my webpage. What I am attempting to achieve is for the page to load and then seamlessly transition from one image to the other without any blank space. Below is the code I ...

Removing all items with a specific ID and its related items in Javascript: How to achieve this recursively?

I am currently facing some challenges in figuring out the most effective approach for this scenario. For example, consider the data structure below: const arr = [{ parentId: 1, children: [ { childId: 11 }, { childId: 21 }, { childId: 31 }, ...

Managing JSON data retrieval and manipulation with REST API in Node.js and MongoDB

My technology stack includes Node.js and MongoDB with a rest api. The input data I'm dealing with looks like this: var doc={"name":"ABX", duedate : new Date() } Before sending it to the server, I stringify the data: /rest/update?doc=JSON.s ...