Home > Mobile >  VUE: Changing a color during an onclick event gets reverted when the mouse leaves the div
VUE: Changing a color during an onclick event gets reverted when the mouse leaves the div

Time:04-01

I'm trying to change the color of a div when it is clicked.

this is the structure of the div

<li v-for="monomer in monomers">
    <div :style="monomerButton" @mouseover="hover = true" @mouseleave="hover = false" 
    @click="selectMonomer($event)" >
        <p >{{monomer.symbol}}</p>
    </div>
</li>

this is the function that is called when the onclick event is called

selectMonomer(event) {
    // If the p element gets clicked, get the div that contains the p element
    let element = event.target.nodeName === "P" ? event.target.parentElement : event.target
    element.style.backgroundColor = "rgba(44, 224, 203, 0.5)"
}

The color does change and remains that way as long as I keep my mouse over the div. When the mouse leaves the div though, the color reverts to it's original color. Clicking it again will change it again but revert right back when the mouse leaves again.

How do I get the div to keep the color?

Edit:

monomerButton: {
    backgroundColor: getNodeColor(this.monomers[0].polymerType, this.monomers[0].naturalAnalog)
}

The background color is dependent on the kind of monomer it is.

Edit2: The entire component (lets call it component A) is in a nested for loop inside of a different component (component B). component B looks something like this:

<component B>
<ul>
  <li v-for="monomer type in monomer types">
    <component A :monomers="monomers of that type"></component A>
  </li>
<ul>
</component B>

so for every kind of monomer, like Glycine glycine analogs, Cysteine cysteine analogs, a component is made. This component (component A) creates a small, square div with text in it for each analog. this is why getNodeColor(this.monomers[0].polymerType, this.monomers[0].naturalAnalog) can just take the first element because all the divs in a single instance of component A need to be the same color.

CodePudding user response:

So, thanks to @Shoejep, I figured out an answer.

// component A
mounted() {
        this.monomers.forEach(monomer => {
            monomer.selected = false
        })
    }

In the mounted hook I gave each monomer a 'selected' attribute. Ofcourse they all start out as not selected.

// component A
<div :style="monomerButton(monomer)" @mouseover="hover = true" @mouseleave="hover = false" @click="selectMonomer(monomer)" >
    <p >{{monomer.symbol}}</p>
</div>

I made the :style attribute use the retun value of getMonomerStyle() which is defined as:

// component A
getMonomerStyle(monomer) {
    return {
         backgroundColor: monomer.selected ? "rgba(131, 222, 226, 0.8)" : getNodeColor(this.monomers[0].polymerType, this.monomers[0].naturalAnalog),
         border: this.monomers[0].monomerType === "Terminal" ? "2px dashed" : "1px solid"
        }
    }

When a mononer is clicked, that monomer is emitted to the parent component. This is so that all other instances of component A also know which monomer is selected.

then it's just simply setting the selected attribute to true for the selected monomer and setting the selected attribute to false for the previously selected monomer.

if (this.previousSelected) {
    this.previousSelected.selected = false
    }
    monomer.selected = true
    this.previousSelected = monomer

CodePudding user response:

You could do something like the snippet I have included below.

Have a selected property on each monomer, then when you calculate the style that should be on div, then you calculate based on whether that monomer is selected or not.

This will also simplify some of the code you presented, because if you click on the p element, then it will bubble up to the div and set the monomer as selected.

Vue.config.devtools = false;
Vue.config.productionTip = false;

new Vue({
  el: "#app",
  data: {
    monomers: [{
        polymerType: "Test",
        naturalAnalog: "Test",
        symbol: "Test",
        selected: false
      },
      {
        polymerType: "Hello",
        naturalAnalog: "Hello",
        symbol: "Hello",
        selected: false
      },
      {
        polymerType: "World",
        naturalAnalog: "World",
        symbol: "World",
        selected: false
      }
    ],
    hover: true
  },
  methods: {
    getNodeColor: function(polymerType, naturalAnalog) {
      return "lightblue";
    },
    selectMonomer: function(monomer) {
      monomer.selected = !monomer.selected;
    },
    monomerButton: function(monomer) {
      return `backgroundColor: ${monomer.selected ? "pink" : this.getNodeColor(monomer.polymerType, monomer.naturalAnalog)}`;
    }
  }
});
ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

li div {
  padding: 8px;
}

li {
  margin-bottom: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <ul>
    <li v-for="monomer in monomers">
      <div :style="monomerButton(monomer)" @mouseover="hover = true" @mouseleave="hover = false" @click="selectMonomer(monomer)" >
        <p >{{monomer.symbol}}</p>
      </div>
    </li>
  </ul>
</div>

  • Related