Vue.js css transition on class change - vue.js

I am trying to use the css transition property to fade the #app background from black to white by adding a class of .lightTheme. The adding of .lightTheme class works as expected, but the transition does not.
Do I have to add the Vue transition element? And if so how? #app is not leaving/entering the dom - I just want to animate it's properties (and I don't want to add unnecessary code if possible!
HTML
<div id="app" v-bind:class="{ lightTheme: isActive }">
<button v-on:click="toggleTheme">Change theme</button>
</div>
JS
new Vue({
el: '#app',
data: {
isActive: false
},
methods: {
toggleTheme: function(){
this.isActive = !this.isActive;
// some code to filter users
}
}
});
CSS
#app {
background: black;
transition: 1s;
}
#app.lightTheme {
background: white;
}
Thanks!

To answer your question if you have to use transition for something like this, the answer is no. The solution you proposed should work out of the box.
There is probably something else that is interfering with your code, but the one you posted is correct.
I attached the working snippet.
new Vue({
el: '#app',
data: {
isActive: false
},
methods: {
toggleTheme: function(){
this.isActive = !this.isActive;
}
}
});
#app {
background: black;
transition: 1s;
}
#app.lightTheme {
background: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app" :class="{ lightTheme: isActive }">
<button #click="toggleTheme">Change theme</button>
</div>

Related

Pass a variable to a child component

I'm trying to pass a class name as a variable to a child component.
Context: I have two types of header ( 2 different bakgrounds ) used all across the site.
Page1:
<HeaderMain bg="bg" />
data() {
return {
pageTitle: 'patterson.travel',
bg: 'bg-white',
}
}
Page:2
<HeaderMain bg="bg" />
data() {
return {
pageTitle: 'patterson.travel',
bg: 'bg-header',
}
}
HeaderMain :
<header>
<nav class="main md:bg-transparent" :class="bg"></nav>
</header>
But the class never gets applied to the <nav>
I tried adding the variable to HeaderMain component like so (as a default):
data() {
return {
bg: 'bg-red', // default?
}
}
But That is the class it allways has...
So, any idea what I'm missing, here?
( I also tried :bg="bg" )
You have to define the bg property on your HeaderMain component:
// HeaderMain.vue
<script>
export default {
props: ['bg']
}
</script>
You will then be able to use it in your template just like you did:
<header>
<nav class="main md:bg-transparent" :class="bg"></nav>
</header>
In order to access it, you need to define props as an array inside your children component.
Look at the code below.
Vue.component('user-name', {
props: ['name'],
template: '<p>Hi {{ name }}</p>'
})
const LastName = {
template: '<span> Patel </span>'
}
const Header = {
props: ['bg'],
template: '<span :class="bg"> {{bg}} Header </span>'
}
new Vue({
el: "#app",
data: function() {
return {
headerBg: 'header-bg'
}
},
components: {
'last-name': LastName,
'header-view': Header
}
});
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
.header-bg {
background: red;
}
.header-bg {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<header-view :bg="headerBg"></header-view>
<user-name name="Varit"></user-name>
<last-name></last-name>
</div>

Vue: Change class with the value of a variable in setInterval

I am learning Vue JS. I want to change class using setInterval. But can’t pass the changing value of Method to Computed Property. After two seconds class will change automatically with the changed value of "changeColor"
My Code:
HTML:
<div>
<button #click="startEffect">Start Effect</button>
<div id="effect" :class="myClass"></div>
</div>
CSS:
.highlight {
background-color: red;
width: 200px !important;
}
.shrink {
background-color: gray;
width: 50px !important;
}
Vue JS:
new Vue({
el: '#exercise',
data: {
changeColor: false
},
methods : {
startEffect: function() {
setInterval(function(){
this.changeColor = !this.changeColor;
//alert(this.changeColor);
}, 2000);
//alert(this.changeColor);
}
},
computed: {
myClass: function() {
return {
highlight: this.changeColor,
shrink: !this.changeColor
}
}
}
})
bind your function to the component...
setInterval(function(){
this.changeColor = !this.changeColor;
}.bind(this), 2000);
and then you can do ...
<div id="effect" :class="[changeColor?'highlight':'shrink']"></div>

Vuejs: autofit div according to remaining space in window

Within vueJs (2.5.16) I'm trying to set the style property of a div so it auto fit the remaining space of a window depending of its size:
I intended to use a computed value which would give me live the correct height and bind it into the style property of the wanted div:
Vue.component('menus', {
template: '<div id="menu-div">MY MENU</div>'
});
Vue.component('expandable', {
template: '<div id="expandable-div" :style="{height:expandableHeight}">EXPANDABLE<div>{{expandableHeight}}</div></div>',
computed: {
expandableHeight() {
return ($(window).height() - $("#expandable-div").position().top) + 'px'
}
}
});
var vm = new Vue({
el: '#app'
});
fiddle
Using $(window).height() and $("#expandable-div").position().top from jQuery I thought I could achieve a result since it works in my console.
Unfortunately I have an error:
TypeError: Cannot read property 'top' of undefined
Why not use CSS's flexbox to achieve that?
Vue.component('menus', {
template: '<div id="menu-div">MY MENU</div>'
});
Vue.component('expandable', {
template: '<div id="expandable-div">EXPANDABLE<div>foo</div></div>',
computed: {}
});
var vm = new Vue({
el: '#app'
});
body {
margin: 0;
}
#app {
display: flex;
flex-direction: column;
height: 100vh;
}
#menu-div {
height: 50px;
background: #768ffb;
margin-bottom: 5px;
}
#expandable-div {
background: #76fbc1;
flex-grow: 1;
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
<menus></menus>
<expandable></expandable>
</div>

Accessing Vue Component scope from external javascript

Can I access Vue components data properties and methods from external javascript? I am trying to create a hybrid application where a portion of the screen is a Vue component, and I want to call a method inside that component on click of a button which is handled by pure js. Is there a way to achieve this?
Thanks!
Yes. You need to assign your Vue object to a variable (i.e. vue) and then you can access vue.methodName() and vue.propertyName:
// add you new Vue object to a variable
const vue = new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true }
]
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
});
// Add event listener to outside button
const button = document.getElementById('outsideButton');
button.addEventListener('click', function() {
vue.toggle(vue.todos[1]);
});
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<label>
<input type="checkbox"
v-on:change="toggle(todo)"
v-bind:checked="todo.done">
<del v-if="todo.done">
{{ todo.text }}
</del>
<span v-else>
{{ todo.text }}
</span>
</label>
</li>
</ol>
</div>
<div class="outside">
<button id="outsideButton">
Click outside button
</button>
</div>
Yes, you can add an event listener to the Vue component that listens for the button click's event. See example here on codepen.
JS
new Vue({
el: '#app',
methods: {
clickMethod(event){
if (event.target.id === 'outsideButton') {
alert('button clicked')
}
}
},
created(){
let localThis = this
document.addEventListener('click', this.clickMethod)
}
})
HTML
<div>
<button id="outsideButton">Button</button>
<div id="app">
</div>
</div>

Can't change button text inside setTimeout function

I have got follow Vue-js App:
<html>
<head>
<script src="https://cdn.jsdelivr.net/vue/1.0.26/vue.min.js"></script>
<style>
.mydiv
{
border: 1px black dashed;
font-size: 2em;
}
</style>
<script>
var App = null; // it's global because function behind will overwrite it's with Vue App instance
window.onload = function()
{
new Vue(
{
el: '#app',
data:
{
btntext: "OK"
},
methods:
{
change: function()
{
this.btntext = "cancel";
setTimeout(function() {console.log("test"); this.btntext = "text changed";},1000);
}
}
})
}
</script>
</head>
<body>
<div id="app">
<div class="mydiv">
<button v-on:click="change">{{btntext}}</button>
</div>
</div>
</body>
</html>
After running I am getting "test" on console, but button do not change it's text to text changed. Why?
The function given to setTimeout does not have the same "this" as your Vue. You could use the bind function:
new Vue({
el: '#app',
data: {
btntext: "OK"
},
methods: {
change: function () {
this.btntext = "cancel";
setTimeout(function () {
console.log("test");
this.btntext = "text changed";
}.bind(this), 1000);
}
}
})
.mydiv{
border: 1px black dashed;
font-size: 2em;
}
<script src="https://cdn.jsdelivr.net/vue/1.0.26/vue.min.js"></script>
<div id="app">
<div class="mydiv">
<button v-on:click="change">{{btntext}}</button>
</div>
</div>
You have to understand the context of this keyword. When in setTimeout callback function, this refers to different object that this before it. To solve this issue, you should solve reference to this before the callback or if you're going to use ES2015, you can change function () {...} with arrow function () => {...}, which will automatically save reference to outer this and use it instead of actual this inside the function. But if you're going to use that, make sure it's supported across all your target browsers, or alternatively use a compiler to ES5, most popular of which is Babel.