Vue Transition Collapsing Snap - javascript

I'm curious how others have solved this problem. When I transition elements whose layout affects the page, there's a snap--or layout adjustment--when the transitioned element is removed. This makes sense, but I'm not sure how best to approach it. Here's an example:
https://codepen.io/noynek/pen/yXeRBY
HTML
<div id="demo">
<transition name="fade">
<div v-if="show" style="float:left">
<input placeholder="field 1" />
<input placeholder="field 2" />
</div>
</transition>
<button v-on:click="show = !show">Toggle</button>
</div>
JS
new Vue({
el: '#demo',
data: {
show: true
}
})
CSS
.fade-enter-active, .fade-leave-active {
transition: all 1s
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
opacity: 0;
transform: translateX(-100px);
}

Related

Rotate image with #click in Vue2

I have a refresh button on dashboard. I want to make it rotate 360 degrees.
How can I rotate image with every click on a refresh button?
This is the code I tried, it only work twice click:
var vm = new Vue({
el: '#app',
data: {
clicked: false,
},
methods: {
rotation() {
this.clicked = !this.clicked
}
}
})
.clicked {
transform: rotate(360deg);
transition: transform 0.5s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.js"></script>
<div id="app">
<img
src="https://via.placeholder.com/100/09f.png/fff"
#click="rotation"
:class="{ clicked }"
alt="refresh-icon-btn"
/>
</div>
This could be one of the approach, have a inline style to toggle between 0 & 360 deg and have a constant class for transition.
var vm = new Vue({
el: '#app',
data: {
deg: 0,
},
methods: {
rotation() {
this.deg += 360;
}
}
})
.transition {
transition: transform 0.5s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js"></script>
<div id="app">
<img src="https://via.placeholder.com/100/09f.png/fff" #click="rotation" class="transition" v-bind:style="{transform: `rotate(${deg}deg)`}" alt="refresh-icon-btn" />
</div>
Another approach is to use setTimeout to remove the class after the animation
var vm = new Vue({
el: '#app',
data: {
clicked: false,
rotationDuration: 500
},
methods: {
rotation() {
this.clicked = !this.clicked
setTimeout(() => this.clicked = !this.clicked, this.rotationDuration)
}
}
})
.clicked {
transform: rotate(360deg);
transition: transform var(--rotation-duration) ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.js"></script>
<div id="app">
<img
src="https://via.placeholder.com/100/09f.png/fff"
#click="rotation"
:class="{ clicked }"
:style="`--rotation-duration: ${rotationDuration}ms`"
alt="refresh-icon-btn"
/>
</div>
You can just use a class binding to toggle the class on and off.
var vm = new Vue({
el: '#app',
data: {
isClicked: false,
},
methods: {
rotation() {
this.isClicked = !this.isClicked
}
}
})
.image {
transition: transform 0.5s ease-in-out;
}
.clicked {
transform: rotate(360deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.js"></script>
<div id="app">
<img
src="https://via.placeholder.com/100/09f.png/fff"
#click="rotation"
class="image"
:class="{ clicked: isClicked }"
alt="refresh-icon-btn"
/>
</div>

How to animate a wizard type form with Vue JS

I am trying to implement a simple animation with Vue but unsuccessful so far. I have two divs which are rendered depending on the value of a given data property
<!--Step 1-->
<div v-if="step == 1" :transition="'slide'">
<select class="form-control" v-model="id.category">
<option value="null">Please Select</option>
<option v-for="cat in cats" :value="cat.id">#{{cat.name}}</option>
</select>
</div>
<!--Step 2-->
<div v-if="step==2" :transition="'slide'" style="background: red">
<select #change="fixImage(id.subcategory)" class="form-control quoteForm" v-model="id.subcategory">
<option value="null">Please Select</option>
<option v-for="subcat in filtered_subcat" :value="subcat.id">#{{subcat.name}}</option>
</select>
</div>
I effectively have a "next button" that will increment the value of step and then show the relevant div. I would like to create like a slide type of effect whereby when the user clicks next, step 1 slides to the left and step 2 slides in. My animation css is as follows:
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
Can anyone point in the right direction?
Wrap the changing content in a <transition> component:
<transition name="slide-fade">
<div v-if="step == 1">
STEP 1 CONTENT
</div>
</transition>
<transition name="slide-fade">
<div v-if="step == 2">
STEP 2 CONTENT
</div>
</transition>
The name of the transition, slide-fade, matches the CSS you supplied. Since you probably want the sliding content to overlap, one should have position: absolute. For example, the content sliding out:
.slide-fade-leave-active {
position: absolute;
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
Here's a Demo:
new Vue({
el: "#app",
data() {
return {
step: 1
}
}
});
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
position: absolute;
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<!--Step 1-->
<transition name="slide-fade">
<div v-if="step == 1">
STEP 1 CONTENT
</div>
</transition>
<!--Step 2-->
<transition name="slide-fade">
<div v-if="step == 2">
STEP 2 CONTENT
</div>
</transition>
<button #click="step++">
Next >
</button>
</div>

Enable / Disable Vue Transitions based on boolean

In Vue, can I somehow disable a transition-animation, based on a boolean?
So now the animation is enabled:
<transition name="fadeUp">
<div v-if="elIsVisible">
<p>Foo Bar</p>
</div>
</transition>
But I wish I do something like this:
<transition name="fadeUp" animation-enabled="false">
<div v-if="elIsVisible">
<p>Foo Bar</p>
</div>
</transition>
Or perhaps a smart work-around?
It's a for module-based website (one component per block), where it could be nifty if the user could enable/disable the animation for certain blocks.
There's a workaround, yes. You can skip the CSS detection by setting v-bind:css to false on the <transition> component.
new Vue({
el: '#app',
data: () => ({
show: true,
animated: true
})
})
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
p {
background-color: beige;
border: 1px solid orange;
padding: 4px 6px;
}
button {
display: block;
margin-top: 2em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<transition name="fade" :css="animated">
<p v-if="show">Hey, there!</p>
</transition>
<label>
<input type="checkbox" v-model="animated" />
Animated
</label>
<button #click="show = !show">Toggle visibility</button>
</div>
You can bind :name in <transition>, which if set to empty, no transition is applied (like when no name is given).
<transition :name="transitionName">
<div v-if="elIsVisible">
<p>Foo Bar</p>
</div>
</transition>
<select #change="e => { transitionName = e.target.value }">
<option
v-for="transition in ['fadeUp', '']"
:key="transition"
:value="transition"
>
{{ transition }}
</option>
</select>

How to use transitions on select option using Vue.js

I have quick question regarding transitions with Vue.js.
In my boostrap template I'm trying to add one more select option dropdown based on selected option. So, I added change event on first select option. So, if I select 'first item' then change classes and add dropdown in row, or else hides it.
Something like this:
selectTodo: function(e) {
let selectValue = e.target.options[e.target.selectedIndex].text
if (selectValue === 'Learn Vue') {
this.styleObject.display = 'unset';
this.col_md = 'form-group col-md-4';
this.showCropStageList = true;
}
else {
this.showCropStageList = false;
this.styleObject.display = 'none';
this.col_md = 'form-group col-md-6';
this.cropStageList = null;
}
}
I managed to do that but I want more smoother transitions on the first two dropdowns.
I've managed to set up some fiddle where you can see smooth slide transition for third select dropdown but if if I change select from "Learn Vue" to something else, the third dropdown hides it but without any animation as well.
You can see it in the snippet below, too!
new Vue({
el: "#app",
data: {
todos: [
{ id:1 ,text: "Learn JavaScript", done: false },
{ id:2 ,text: "Learn Vue", done: false },
{ id:3 ,text: "Play around in JSFiddle", done: true },
{ id:4 ,text: "Build something awesome", done: true }
],
col_md: 'form-group col-md-6',
styleObject: {
display: 'none'
},
showCropStageList: false,
},
methods: {
toggle: function(todo){
todo.done = !todo.done
},
selectTodo: function(e) {
let selectValue = e.target.options[e.target.selectedIndex].text
if (selectValue === 'Learn JavaScript') {
this.styleObject.display = 'unset';
this.col_md = 'form-group col-md-4';
this.showCropStageList = true;
}
else {
this.showCropStageList = false;
this.styleObject.display = 'none';
this.col_md = 'form-group col-md-6';
this.cropStageList = null;
}
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
.fade-enter {
opacity: 0;
}
.fade-enter-active {
transition: opacity 1s;
}
.fade-leave {}
.fade-leave-active {
transition: opacity 1s;
opacity: 0;
}
#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://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div class="container">
<!-- Content here -->
<div id="app">
<div class="form-row">
<transition name="fade" appear>
<div v-bind:class=col_md>
<label for="cropType" class="col-form-label-sm font-weight-bold">Select Learn Javascript </label>
<select class="form-control" v-on:change="selectTodo" id="cropType" v-model="pickedCropType" #change="getCropsByType()">
<option v-for="(todo, index) in todos" :key="index" :value="todo.id" >
{{todo.text}}
</option>
</select>
</div>
</transition>
<div v-bind:class=col_md>
<label for="cropCulture" class="col-form-label-sm font-weight-bold">2. Second</label>
<select class="form-control" id="cropCulture">
<option v-for="(todo, index) in todos" :key="index" :value="todo.id" >
{{todo.text}}
</option>
</select>
</div>
<transition
enter-active-class="animated fadeInLeft"
leave-active-class="animated fadeOutLeft"
>
<div class="form-group col-md-4" v-if="showCropStageList" v-bind:class="{styleObject }">
<label for="cropStage" class="col-form-label-sm font-weight-bold">3. Third</label>
<select class="form-control" id="cropStage">
<option v-for="(todo, index) in todos" :key="index" :value="todo.id" >
{{todo.text}}
</option>
</select>
</div>
</transition>
</div>
</div>
</div>
You can see change class for first two dropdowns but without any transitions. So, is it possible to add some transitions for first two dropdowns?
EDIT :
As you can see I'm changing class from *form-group col-md-6* to *form-group col-md-4* and I' wondering if is it possible that that tranisition from md-6 to md-4 can be a bit smoother.
https://jsfiddle.net/Loque/akt0su98/
In your codes, you directly update the class from col-md-4 to col-md-6 in selectTodo. It will cause first two <div> take full width of the row before 3rd div finishes its animation.
The solution, uses this.$nextTick and setTimeout.
when add the third div, delay execute show the third div before first two <div> finish their animations.
when remove the third div, delay apply col-md-6 to the first two <div> before the third <div> finishes its animations.
Below is one sample: (PS: I used transition-group here, because it will be better for Reusable Transitions)
Warning: Please test below demo under full page, otherwise bootstrap will treat it as extre-small screen (place each <div> in each row), though I think the effects in small screen is still not bad.
new Vue({
el: "#app",
data: {
todos: [
{ id:1 ,text: "Learn JavaScript", done: false },
{ id:2 ,text: "Learn Vue", done: false },
{ id:3 ,text: "Play around in JSFiddle", done: true },
{ id:4 ,text: "Build something awesome", done: true }
],
col_md: 'form-group col-md-6',
styleObject: {
display: 'none'
},
showCropStageList: false,
pickedCropType: ''
},
methods: {
getCropsByType: function () {},
toggle: function(todo){
todo.done = !todo.done
},
selectTodo: function(e) {
let selectValue = e.target.options[e.target.selectedIndex].text
if (selectValue === 'Learn Vue') {
this.col_md = 'form-group col-md-4';
this.$nextTick(() => { //delay display the third div before first two div finish animation
setTimeout(()=>{
this.styleObject.display = 'unset';
this.showCropStageList = true;
}, 500)
})
}
else {
this.showCropStageList = false;
this.styleObject.display = 'none';
this.$nextTick(() => { //delay apply `md-6` to first two div before 3rd div finish animation
setTimeout(()=>{
this.col_md = 'form-group col-md-6';
}, 1000)
})
this.cropStageList = null;
}
}
}
})
.sample {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
.fade-item {
transition: all 0.5s;
display:inline-block;
}
.fade-enter {
opacity: 0;
transform: translateX(-130px);
}
.fade-enter-active {
transition: all 1.5s;
}
.fade-leave-to {
transform: translateX(130px);
opacity: 0;
flex: 0 0 20%;
}
.fade-leave-active {
transition: all 1s;
}
#app {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<!-- Content here -->
<div id="app">
<div class="container">
<div class="sample">
<transition-group name="fade" tag="div" class="form-row">
<div v-bind:class="col_md" :key="1" class="fade-item">
<label for="cropType" class="col-form-label-sm font-weight-bold">Select Learn Javascript </label>
<select class="form-control" v-on:change="selectTodo" id="cropType" v-model="pickedCropType" #change="getCropsByType()">
<option v-for="(todo, index) in todos" :key="index" :value="todo.id" >
{{todo.text}}
</option>
</select>
</div>
<div v-bind:class="col_md" :key="2" class="fade-item">
<label for="cropCulture" class="col-form-label-sm font-weight-bold">2. Second</label>
<select class="form-control" id="cropCulture">
<option v-for="(todo, index) in todos" :key="index" :value="todo.id" >
{{todo.text}}
</option>
</select>
</div>
<div class="form-group col-md-4 fade-item" v-if="showCropStageList" v-bind:class="{styleObject }" :key="3">
<label for="cropStage" class="col-form-label-sm font-weight-bold">3. Third</label>
<select class="form-control" id="cropStage">
<option v-for="(todo, index) in todos" :key="index" :value="todo.id" >
{{todo.text}}
</option>
</select>
</div>
</transition-group>
</div>
</div>
</div>
I don't know if there is a specific way to do in Vue but what you want can be easily achieved using some CSS magic. It is simple in a matter of fact, all you are going to do is add a class to your changing div let's say for example the class name is transition and in your CSS you define transition styles as follow:
.transition {
transition: all 0.25s linear;
}
You can find an updated fiddle here
Note you can change the timing function linear and the time 0.25s to suit your needs, you can read more about CSS transitions and effects here

CSS - reset animation

I have an issue with animation created using css. Everything is working fine, I just need to finish this and set input type to reset animation.
Here is my css that should reset animation:
$('button').on('click', function(){
var heading = $('h1').clone().removeClass();
$('h1').remove();
$('header').append(heading);
$('h1').addClass('fadein_element');
});
CSS animation
#keyframes fadein {
0% { opacity: 0; }
100% { opacity: 1; }
enter code here
.fadein{-webkit-animation: fadein 3s ease-in ;
-moz-animation: fadein 3s ease-in ;
animation: fadein 3s ease-in ;
This was my basic html for that part:
<input type="radio" name="radio-set" checked="checked" id="st-control-1"/>
WebGear
And here is the edited one:
input type="radio" name="radio-set" checked="checked" id="st-control-1"/>
<h1 class="fadein_element"><button class="fadein_element">WebGear</button></h1>
I got lost in it and nothing resets the animation. Other than that it works fine.To sum it up, do you guys have any ideas how to get this working ? Preferably with default html code...
Edit: Posting a minimal code wich I am trying to get working
</head>
<body>
<div class="st-container">
<input type="radio" name="radio-set" checked="checked" id="st-control-1"/>
Something
<input type="radio" name="radio-set" id="st-control-2"/>
Happiness
<input type="radio" name="radio-set" id="st-control-3"/>
Tranquillity
<input type="radio" name="radio-set" id="st-control-4"/>
Positivity
<input type="radio" name="radio-set" id="st-control-5"/>
WebGear
<div class="st-scroll">
<section class="st-panel" id="st-panel-5">
<div class="st-deco" data-icon="H"></div>
<div id="section1">
<div id="menu"> <img id="menuitem" src="Images/Menuitem.png"/>
<div id="hlava">
<div id="flashContent">
---Here goes the content---
There are just closing tags
And CSS
#keyframes fadein {
0% { opacity: 0; }
100% { opacity: 1; }
}
.fadein{-webkit-animation: fadein 3s ease-in ;
-moz-animation: fadein 3s ease-in ;
animation: fadein 3s ease-in ;
Once I click on "radio button" I want my (in this case st-panel-5) to reset animation. Any of those 5 buttons will do that so I belive I could apply that to class st-panel.
To solve this you set all but the checked radio input's targeted st-panel to display: none; opacity: 0, and then set animation: fadein ...; to the checked radio input's targeted st-panel-nn id.
Than
Click the 2 first radio inputs to check the behavior
#st-control-1:checked ~ .st-scroll .st-panel:not(#st-panel-1),
#st-control-2:checked ~ .st-scroll .st-panel:not(#st-panel-2) {
opacity: 0;
display: none;
}
#st-control-1:checked ~ .st-scroll #st-panel-1,
#st-control-2:checked ~ .st-scroll #st-panel-2 {
animation: fadein 1.5s ease-in;
}
#keyframes fadein {
0% { opacity: 0; }
100% { opacity: 1; }
}
<div class="st-container">
<input type="radio" name="radio-set" checked="checked" id="st-control-1"/>
Something
<input type="radio" name="radio-set" id="st-control-2"/>
Happiness
<input type="radio" name="radio-set" id="st-control-3"/>
Tranquillity
<input type="radio" name="radio-set" id="st-control-4"/>
Positivity
<input type="radio" name="radio-set" id="st-control-5"/>
WebGear
<div class="st-scroll">
<section class="st-panel" id="st-panel-1">
<div class="st-deco" data-icon="H"></div>
<div id="section1">
<div id="menu"> <img id="menuitem" src="Images/Menuitem.png"/>
<div id="hlava">
<div id="flashContent">
Some content 1
</div>
</div>
</div>
</div>
</section>
<section class="st-panel" id="st-panel-2">
<div class="st-deco" data-icon="H"></div>
<div id="section1">
<div id="menu"> <img id="menuitem" src="Images/Menuitem.png"/>
<div id="hlava">
<div id="flashContent">
Some content 2
</div>
</div>
</div>
</div>
</section>
</div>
</div>
"Here is my css that should reset animation:" - it's actually Javascript - jQuery, but maybe I misunderstood.
After an animation is executed use this code:
element.offsetWidth = element.offsetWidth;
but I think it's pure Javascript (without jQuery) so in your example it would be:
document.getElementsByTagName("h1")[0].offsetWidth = document.getElementsByTagName("h1")[0].offsetWidth
You can find more information here.

Categories