Create sliding left effect using Vuejs animation - vue.js

I've read this official document about Vuejs animation. But using it css hooks, I can only make element appear/disappear with fade and different duration.
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
opacity: 0
}
How to use Vuejs Animation to create a sliding effect? Like the one here. Is it possible? Please provide some sample code.

You can absolutely do this with VueJS.
Have a look at the example under. You can see two examples, one is the adopted code for your case(to make it slide). And other is a simple image slider, that loops through array of images in 3 seconds interval.
Important thing to note here, is that we wrap the image element in for loop to force the element to be destroyed, because otherwise your elements will not be removed from DOM and will not transition (virtual DOM).
For better understanding of transitions in VueJS in recommend you to check out getting started guide - transition section.
new Vue({
el: '#demo',
data: {
message: 'Click for slide',
show: true,
imgList: [
'http://via.placeholder.com/350x150',
'http://via.placeholder.com/350x151',
'http://via.placeholder.com/350x152'
],
currentImg: 0
},
mounted() {
setInterval(() => {
this.currentImg = this.currentImg + 1;
}, 3000);
}
})
#demo {
overflow: hidden;
}
.slide-leave-active,
.slide-enter-active {
transition: 1s;
}
.slide-enter {
transform: translate(100%, 0);
}
.slide-leave-to {
transform: translate(-100%, 0);
}
.img-slider{
overflow: hidden;
position: relative;
height: 200px;
width: 400px;
}
.img-slider img {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right:0;
}
<!DOCTYPE html>
<html>
<head>
<title>VueJS 2.0 - image slider</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="slide">
<p v-if="show">{{message}}</p>
</transition>
<h3>
Img slider
</h3>
<transition-group tag="div" class="img-slider" name="slide">
<div v-for="number in [currentImg]" v-bind:key="number" >
<img :src="imgList[Math.abs(currentImg) % imgList.length]"/>
</div>
</transition-group>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="script.js"></script>
</body>
</html>

Thanks for the answer above it helped me a lot!
Since the original example had buttons to slide in both directions,
I improved it somewhat by adding "Next" and "Previous" buttons. I swap the animation to have it go the oposite way when pressing "Previous":
new Vue({
el: '#demo',
data: {
back: false,
currentIndex: 0
},
methods: {
next(){
this.back = false;
this.currentIndex++;
},
prev(){
this.back = true;
this.currentIndex--;
}
},
})
#demo {
overflow: hidden;
}
.slide-leave-active,
.slide-enter-active {
transition: 1s;
}
.slide-enter {
transform: translate(100%, 0);
}
.slide-leave-to {
transform: translate(-100%, 0);
}
.slideback-leave-active,
.slideback-enter-active {
transition: 1s;
}
.slideback-enter {
transform: translate(-100%, 0);
}
.slideback-leave-to {
transform: translate(100%, 0);
}
.div-slider{
overflow: hidden;
position: relative;
height: 100px;
width: 90%;
}
.div-slider .card {
position: absolute;
height: 100px;
width: 90%;
background-color: #60adff;
}
<!DOCTYPE html>
<html>
<head>
<title>VueJS 2.0 - image slider</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="demo">
<h3>
div slider
</h3>
<transition-group tag="div" class="div-slider" :name="back? 'slideback' : 'slide'">
<div v-if="currentIndex === 0" key="1">
<div class="card">
DIV 1
</div>
</div>
<div v-if="currentIndex === 1" key="2" >
<div class="card">
DIV 2
</div>
</div>
<div v-if="currentIndex === 2" key="3" >
<div class="card">
DIV 1
</div>
</div>
</transition-group>
<button #click="prev()" >prev</button>
<button #click="next()">next</button>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
</body>
</html>

Related

Vuejs: How to add Transition to slot content?

I have a modal component that handles the overlay and css etc. and allows for modal content to be passed in via a slot:
<div class="slot-content">
<slot></slot>
</div>
And it's being used like
<Modal ...>
<div class="some-modal-content-div">
...
</div
</Modal>
Currently the modal appearance is a bit "abrupt".
I do want the overlay be there instantly, but would like to add a bit of a transition to the appearance of the content div.
How do I add a <Transition> to just the slot content?
If I understood you correctly maybe like following snippet:
const app = Vue.createApp({
data() {
return {
show: false,
};
},
})
app.component('modal', {
template: `
<div class="slot-content">
<p>other content</p>
<transition name="slide-fade" appear>
<slot></slot>
</transition>
</div>
`
})
app.mount('#demo')
.slide-fade-enter-active {
transition: all 0.5s ease-out;
}
.slide-fade-leave-active {
transition: all 1s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
.mod {
border: 1px solid purple;
}
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<button #click="show = !show">show</button>
<modal v-if="show" class="mod">
<div class="some-modal-content-div">
<b>slot content</b>
</div>
</modal>
</div>
I was actually too fixated on using the vue Transition instead of just applying the css animation directly to the slot content container:
<div class="slot-content animate-class">
<slot></slot>
</div>
...
.animate-class {
animation: foo 0.1s;
}

Swiper.js Forced Reflow performance issues when responsive

A question about using swiper.js carousel/slider gallery. I'm getting bad performance issues with "forced reflow" when making the slider responsive.
If the viewport is resized then the forced reflow is extreme. How do I go about debugging this?
Swiper github says this is the best place for asking for support.
I've added example code here.
Codepen
// Just duplicating swiper 20 times
const listing = document.getElementsByClassName("listing")[0];
for (let i = 0; i < 19; i++) {
let clone = listing.cloneNode(true);
clone.getElementsByClassName("swiper-container")[0].id = `carousel-${i+1}`;
document.getElementsByClassName("grid")[0].appendChild(clone);
newSwiper(i + 1);
}
function newSwiper(i) {
let swiper = new Swiper(`#carousel-${i}`, {
initialSlide: Math.floor(Math.random() * 6),
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}
});
}
#import url('https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.1/css/swiper.min.css');
.grid {
display: grid;
grid-gap: 0.5rem;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.swiper-container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.listing {
background: orange;
width: 100%;
position: relative;
}
.listing::before {
content: "";
display: inline-block;
width: 1px;
height: 0;
padding-bottom: 70%;
}
img {
height: 100%;
width: 100%;
object-fit: cover;
}
<div class="grid">
<div class="listing">
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">
<img src="https://i.imgur.com/8aoOSaob.jpg" alt="thumb">
</div>
<div class="swiper-slide">
<img src="https://i.imgur.com/FB5IGMgb.jpg" alt="thumb">
</div>
<div class="swiper-slide">
<img src="https://i.imgur.com/GBpr1JR.png" alt="thumb">
</div>
<div class="swiper-slide">
<img src="https://i.imgur.com/UYqiudHb.jpg" alt="thumb">
</div>
<div class="swiper-slide">
<img src="https://i.imgur.com/BBFBbuA.jpeg" alt="thumb">
</div>
<div class="swiper-slide">
<img src="https://i.imgur.com/tpZvfRn.jpg" alt="thumb">
</div>
</div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.1/js/swiper.min.js"></script>
I spent way too much time trying to fix this problem. Playing with the css over and over. I've come to the conclusion it's swiper.js. Perhaps how things are recalculated somewhere.
I switched the code over the glide.js and no performance problems. There's no lazy loading included so more development time needed to plug that gap.

Vuetify transitions: How to set the transition speed

I have an <audioplayer> component that I would like to be displayed slowly sliding from the bottom of a parent component.
I defined it inside <v-slide-y-transition>, but how I can make it slide slowly from the bottom? I cannot find any attributes to be defined for the <v-slide-y-transition> Vuetify component.
<v-parallax src="img/hero.jpeg">
<v-layout column align-center justify-center>
<img src="#/assets/images/logo.png" height="200">
<h1 class="mb-2 display-1 text-xs-center">HEADER 1</h1>
<h2 class="mb-2 display-1 text-xs-center">HEADER 2</h2>
<div class="subheading mb-3 text-xs-center">SUB-HEADER</div>
<v-btn round #click="switchAudioPlayer()" large href="#">LISTEN</v-btn>
<v-slide-y-transition>
<audioplayer id="audioplayer" v-if="listening" v-show="showAudioPlayer" :autoPlay="autoPlay" :file="audioFile" :canPlay="audioReady" :ended="switchAudioPlayer"></audioplayer>
</v-slide-y-transition>
</v-layout>
</v-parallax>
Vuetify transitions don't appear to have configuration properties, so you'd have to create your own in order to tweak the timing.
You could use a Vue <transition> component, using CSS transition property to set the timing of the animation.
For example, the following CSS sets the duration of the slide-fade animation to 2 seconds.
.slide-fade-enter-active {
transition: all 2s ease;
}
Demo:
new Vue({
el: '#app',
data: () => ({
show: false,
}),
})
.slide-fade-enter-active {
transition: all 2s 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: translateY(30px);
opacity: 0;
}
footer {
position: absolute;
bottom: 0;
}
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<button v-on:click="show = !show">
Toggle
</button>
<footer>
<transition name="slide-fade">
<p v-if="show">hello</p>
</transition>
</footer>
</div>
If you use Vue 2.2.0+ the transition component has a duration prop so, it would look like this (if you use the vuetify transition name from your question):
<transition appear name="slide-y-transition" :duration="{ enter: 500, leave: 800 }>
Note: I noticed that you could add duration property to vuetify transition components. Its value is in milliseconds. But it's not very accurate, so I use it along with some CSS as below.
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
show: false,
}),
})
p {
background: lightgreen;
}
.slide-x-transition-enter-active {
background-color: #b2fab2;
transition: background-color 2s, all 2s;
}
.slide-x-transition-enter-to {
background-color: white;
}
.slide-x-transition-leave-active {
background-color: white;
transition: background-color 2s, all 2s;
}
.slide-x-transition-leave-to {
background-color: #fccece;
}
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<v-app id="app">
<button v-on:click="show = !show">
Toggle
</button>
<v-slide-x-transition duration="2000">
<p v-if="show">hello</p>
</v-slide-x-transition>
</v-app>

Transform Based Animation using Vue Transition Wrapper

I'm trying to port some animation implemented mostly through css and little javascript to a Vue component. The animation is simple - user clicks a button and a little panel opens from the bottom of his browser and slides upwards.
I have a working Vue component implemented using the same css and no javascript.
Now, I'm aware of the transition wrapper that Vue provides. But I'm unable to figure out how to get similar functionality using the transition wrapper (if at all).
Can someone help me out here?
// register modal component
Vue.component('modal', {
template: '#modal-template',
props: ['show']
})
// start app
new Vue({
el: '#app',
data: {
showModal: false
}
})
.drawer-wrapper {
position: fixed;
top: 100%;
left: 0;
right: 0;
height: 50%;
z-index: 9998;
transition: transform .3s ease-out;
}
.drawer-wrapper.open {
transform: translateY(-100%);
}
.drawer-container {
height: 100%;
width: 100%;
background-color: white;
}
.drawer-header h3 {
margin-top: 0;
color: #42b983;
}
.drawer-body {
margin: 20px 0;
}
.drawer-default-button {
float: right;
}
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<!-- template for the modal component -->
<script type="text/x-template" id="modal-template">
<div class="drawer-wrapper" :class="{ open: show }">
<div class="drawer-container">
<div class="drawer-header">
<slot name="header">
default header
</slot>
</div>
<div class="drawer-body">
<slot name="body">
default body
</slot>
</div>
<div class="drawer-footer">
<slot name="footer">
default footer
<button class="drawer-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</script>
<!-- app -->
<div id="app">
<button id="show-modal" #click="showModal = true">Show Modal</button>
<!-- use the modal component, pass in the prop -->
<modal #close="showModal = false" :show="showModal">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
</modal>
</div>
I got this to work using a transition wrapper, but the code isn't as elegant as I'd expected. Particularly the use of the following attributes in the drawer-wrapper class:
top: 100%;
transform: translateY(-100%);
Fiddle is here
If anyone can simplify the code further, I'd really appreciate it.

Why won't my click event in Vue.js fire?

I'm trying to use Vue's on-click directive on a div but it does not fire as intended. When I click the .demo class nothing happens; I should get a 'test clicked' in the console. I don't see any errors in the console, so I don't know what am I doing wrong.
var app = new Vue({
el: '#app',
data: {
title: 'This is the first vue app',
name: 'ALRAZY',
link: 'http://google.com',
attachRed: false
},
methods: {
changeLink: function() {
this.link = 'http://apple.com'
}
}
})
body {
font-family: 'Trykker', 'Spectral SC', serif;
}
h1,h2,h3,h4,h5,h6 {
font-family: 'Spectral SC', serif;
}
p {
font-family: 'Trykker', serif;
}
.demo {
width: 100px;
height: 100px;
background-color: grey;
display: inline-block;
margin: 10px;
}
.red {
background: red;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css?family=Spectral+SC:400,400i,500,500i,600|Trykker" rel="stylesheet" >
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div class="container">
<div class="row">
<div id="app">
<h1>{{ title }} </h1>
<input type="text" v-model="name" name="">
<p> {{ name }}</p>
<button onclick="changeLink" class="btn btn-danger btn-lg">click to change</button>
<a :href="link" target="_blank">Link</a>
<!-- style-vue -->
<div class="demo" onclick="attachRed = !attachRed" :class="{red: attachRed}"></div>
<p v-if="show">You can see me!!!</p>
<p v-else>Do You see me??</p>
</div>
</div>
</div>
You're using the standard onclick attribute which is not going to trigger vue methods. Try using v-on:click="changeLink()" or #click="changeLink()" (I'm not entirely sure if the second is the correct syntax). That should resolve your problem.
Similarly, you can do #click="attachRed = !attachRed".