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>
Related
i'm quite new to vue and can't figure out how to do it, i have several buttons and i need to select only one when clicked, i did it via
:class="isActive ? 'on' : 'off'"
v-on:click ="isActive = !isActive"
but this activates all the buttons, then I understand that I need to somehow distinguish the target button from the non-target one, but I can’t figure out how to do this. I can't find suitable implementation examples can you provide code examples
data() {
return {
isActive: true,
color: ‘’,
};
},
<template>
<div id="btn-box">
<button
type="button"
class="btn off"
#click="component='BorderLeftComonent', toggleShowPopup()">
<div
style="padding: 0 5px; width: 25px; margin: 0 auto; font-size: 25px;"
:style="{ 'border-left': `4px solid ${color}` }">A</div>
</button>
<button
type="button"
class="btn off"
#click="component='TextBalloonComponent'">
<div
class="bubble"
style="margin: 0 auto; width: 25px; font-size: 25px;">A</div>
</button>
<button
type="button"
class="btn off"
#click="component='DashedComponent'">
<div
style="border: 4px dashed #f5d018; margin: 0 auto; width: 45px; font-size: 25px;">A</div>
</button>
</div>
</template>
Wrong Syntax:
:class="isActive ? 'on' : 'off'"
v-on:click ="isActive = !isActive"
Correct Syntax (using shorthand):
:class="{ 'on': isActive, 'off': !isActive }"
#click="isActive = !isActive"
OR this, and take a look at the example below:
:class="{ 'on': isActive, 'off': !isActive }"
#click="toggle"
Define the #click event toggle in the methods as this:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<!-- these buttons have `:class` binding and `#click` event -->
<button :class="{ 'on': isActive, 'off': !isActive }" #click="isActive = !isActive">Toggle</button> OR
<button :class="{ 'on': isActive, 'off': !isActive }" #click="toggle">Toggle</button> OR
<!-- these buttons just have `#click` event -->
<button #click="isActive = !isActive">Toggle</button> OR
<button #click="toggle">Toggle</button> OR
<!-- these buttons do not (have class and event binding) do anything -->
<button>Toggle</button> OR
<button>Toggle</button>
<p v-if="isActive">{{ message }}</p>
</div>
<script>
let app = new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
isActive: true,
},
methods: {
toggle() {
this.isActive = this.isActive ? false : true
}
},
})
</script>
<style scoped>
/*simply styling your classes*/
button {
padding: 0.5em;
border-radius: 5px;
color: hsl(205, 46.5%, 73.5%);
background-color: hsl(205, 14%, 28%);
}
.on {
color: green;
}
.off {
color: red;
}
</style>
Use v-for directive to iterate over an array of button objects where each object includes it's own isActive property that can be toggled by the onclick event.
<button
v-for="(button, index) in buttons"
:key="index"
:class="button.isActive ? 'on' : 'off'"
#click="button.isActive = !button.isActive"
>
<div :class="`btn btn-${button.type}`">{{ button.label }}</div>
</button>
data() {
return {
buttons: [
{
label: "A",
isActive: false,
type: "border-left",
},
{
label: "A",
isActive: false,
type: "text-balloon",
},
{
label: "A",
isActive: false,
type: "dashed",
},
],
};
}
<style scoped>
.btn {
padding: 0 5px;
width: 25px;
margin: 0 auto;
font-size: 25px;
}
.btn-border-left {
border-left: 4px solid #f55;
}
.btn-dashed {
border: 4px dashed #f5d018;
width: 45px;
}
</style>
It seems that you need a button group, a classic component in UI libraries.
Have a look at this one for example.
For example below, you have 4 buttons next to each other, and each button is highlighted when you click on it, see gif below.
And in your code, you have access to a property (here "text") that reflects which button is selected.
Code taken from the link above:
<v-btn-toggle
v-model="text"
tile
color="deep-purple accent-3"
group
>
<v-btn value="left">
Left
</v-btn>
<v-btn value="center">
Center
</v-btn>
<v-btn value="right">
Right
</v-btn>
<v-btn value="justify">
Justify
</v-btn>
</v-btn-toggle>
Does that answer your question?
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>
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
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);
}
Hello :) I am relatively new to react js, i am trying to apply animation on a div that is a child of another div, parent div " portfolio-product-item " displays featured image extracted from wp rest api, and child div " portfolio-product-item-details " has the contents of the post.
What i want to do is display the content when hovered over the featured image in parent div , my code is like this , how can i achieve it?
import React from 'react';
import Home from './Home';
require ('../../app.css');
require ('../../animate.min.css');
class Portfolio extends React.Component{
render(){
console.log(this.props.data.length);
var contents=[];
for (var i = 0; i < this.props.data.length; i++) {
contents.push(
<div className="col-xs-12 col-md-4">
<div id="portfolio-product-item" >
<img src={this.props.data[i].featured_image} />
<div ref= "productDetails" id ="portfolio-product-item-details" dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}} />
</div>
</div>
);
}
return(
<div className = "container">
<div className="row">
<section className="portfolio">
<h1>Our Latest Work</h1>
<p id="below-header">These are some of the works that has been keeping us busy over the years. See for yourself what we can do.</p>
<div className="col-xs-12 ">
{contents}
</div>
</section>
</div>
</div>
)
}
}
export default Portfolio;
React allows to add / remove elements from the virtual DOM. Use the onMouseEnter and onMouseLeave to set show / hide state.
<img
onMouseEnter={() => this.setState({ show: true })}
onMouseLeave={() => this.setState({ show: false })}
/>
Then show / hide details based on the state:
{this.state.show ?
<div ref= "productDetails" id ="portfolio-product-item-details"
dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}}
/>
: null}
My solution was something like this
import React from 'react';
import Home from './Home';
require ('../../app.css');
require ('../../animate.min.css');
class Portfolio extends React.Component{
render(){
var contents=[];
for (var i = 0; i < this.props.data.length; i++) {
var productImage ={
backgroundImage:'url('+ this.props.data[i].featured_image + ')',
backgroundSize: '100% 100%'
}
contents.push(
<div className="col-xs-12 col-md-6 col-lg-4">
<div id="portfolio-product-item" style ={productImage} >
<div ref= "productDetails" id ="portfolio-product-item-details" dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}} />
</div>
</div>
);
}
return(
<div className = "container">
<div className="row">
<section className="portfolio">
<h1>Our Latest Work</h1>
<p id="below-header">These are some of the works that has been keeping us busy over the years. See for yourself what we can do.</p>
<div className="col-xs-12 ">
{contents}
</div>
</section>
</div>
</div>
)
}
}
export default Portfolio;
and css rules were like this
section.portfolio div#portfolio-product-item{
height:370px;
width:100%;
background: #f0f0f0;
margin:15px;
position:relative;
transform: rotate(4deg) ;
box-shadow: 5px 5px 5px #909090;
-webkit-font-smoothing: antialiased;
}
section.portfolio div#portfolio-product-item-details{
height:100%;
width:100%;
padding:10px;
text-align: center;
color:#ffffff;
position: absolute;
top:0;
background-color: #000000;
opacity:0;
}
section.portfolio div#portfolio-product-item-details:hover{
cursor:pointer;
opacity:0.9;
transition: all .5s ease-in-out;
}