Vuejs 2.5 sink animation mult
by jpeter06
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="main">
<p-menu></p-menu>
<div style="display:flex;flex-grow:1;position:relative; width:100%; height:100%">
<div class="pageContExt">
<div class="pageCont" v-bind:class="{ active: isActive }">
<transition :name="transitionName" >
<component v-bind:is="page_1"></component>
</transition>
</div>
</div>
<div class="pageContExt">
<div class="pageCont" v-bind:class="{ active: isActive }">
<transition :name="transitionName" >
<component v-bind:is="page_2"></component>
</transition>
</div>
</div>
</div>
<div style="display:flex;flex-grow:1;position:relative; width:100%; height:100%">
<div class="pageContExt">
<div class="pageCont" v-bind:class="{ active: isActive }">
<transition :name="transitionName" >
<component v-bind:is="page_3"></component>
</transition>
</div>
</div>
<div class="pageContExt">
<div class="pageCont" v-bind:class="{ active: isActive }">
<transition :name="transitionName" >
<component v-bind:is="page_4"></component>
</transition>
</div>
</div>
</div>
</div>
<template id="pMenu">
<div class="menu" v-bind:class="{ active: isActive }">
<ul>
<li v-bind:class="[page==item ?'focused':'']" v-for="item in items" v-on:click="click(item)">
{{item}}
</li>
</ul>
</div>
</template>
<!-- PAGES -->
<template id="page2">
<div class="page page2" >
Page2
</div>
</template>
<template id="page1">
<div class="page page1" >
Page1
<innertext/>
</div>
</template>
<template id="page3">
<div class="page page3" style="background:orange;color:white !important">
Page3
</div>
</template>
<template id="page4">
<div class="page page4" style="background:#38d838;color:white !important">
Page4
...
CSS
html, body ,#main
{
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
overflow: hidden;
background:#fff;
font-family:Arial;
color:#888;
}
#main{
display:flex; flex-direction:column;
--animation-speed: 1.4s;
--scale: 0.92;
}
.pageContExt{flex-grow:1;position:relative;overflow: hidden;
border: 10px solid transparent;display:flex;}
.pageCont{flex-grow:1;position:relative;overflow: hidden;
}
.pageCont.active{border: 1px inset rgba(250,250,250,0.6); }
.pageCont::after {
box-shadow: 0 0px 15px rgba(0,0,0,0.3) inset;
opacity: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
content:"";
pointer-events: none;
background:rgba(0,0,0,0.03);
/*border: 1px inset rgba(250,250,250,0.6);*/
}
/* Transition to showing the bigger shadow on hover */
.pageCont.active::after {
animation: show-hole calc(var(--animation-speed) );
}
@keyframes show-hole{
0% {opacity:0 ;animation-timing-function: ease-out; }
33% { opacity: 1;animation-timing-function: ease-out; }
70% { opacity: 1;animation-timing-function: ease-in; }
100% { opacity: 0.2; animation-timing-function: ease-in; }
}
.page{
will-change: transform;
width:100%;height:100%;
position: absolute;top:0px;left:0px;
box-sizing: border-box;
display: block;
padding:12px;
text-align:center;
background-clip: border-box;
overflow-y:auto;
transform-origin:center;
line-height:1.2;
}
.page::first-line{font-weight:bold; font-size:26px;}
@keyframes bounce-li{
0% {transform: translate(0%,calc( 100% + 40px)) scale(var(--scale),var(--scale));animation-timing-function: ease-out; }
33% {transform: translate(0%,calc( 100% + 40px)) scale(var(--scale),var(--scale));animation-timing-function: ease-out; }
70% {transform: translate(0%,0%) scale(var(--scale),var(--scale));animation-timing-function: ease-in; }
100% {transform: translate(0%,0%); animation-timing-function: ease-in;...
JavaScript
///////// pMenu //////////
var pMenu = Vue.extend({
template: '#pMenu',
data:function(){
return {
page:'page1',
isActive:false,
timeoutId:null,
items:['page1','page2','page3','page4']
}
},
methods:{
click:function(item){
var isR=this.items.indexOf(item)>this.items.indexOf(this.page);
this.page=item;
vv.transitionName=isR?'pageL':'pageR';
vv.page_4=this.getRandom(vv.page_4);
vv.page_1=this.getRandom(vv.page_1);
vv.page_2=this.getRandom(vv.page_2);
vv.page_3=this.getRandom(vv.page_3);
vv.page=item;
},
isFocused:function(item){
return item==this.page?'focused':''
},getRandom:function(item){
var pos=Math.floor(Math.random()*this.items.length)%this.items.length;
var next= this.items[pos];
if(next==item)
next= this.items[(pos+1)%(this.items.length)];
return next;
}
},
watch: {
page: function(newValue) {
/*
clearTimeout(this.timeoutId);
this.isActive=true;
var self=this;
this.timeoutId = setTimeout(function(){ self.isActive=false; }, 1000);
*/
}
}
})
Vue.component('p-menu', pMenu);
/////////// PAGE 1 ///////////////
Vue.component('page1', { template: '#page1',
data:function(){
return {
transitionName:'pageS',
subpage:'subpage1',
checked:false,
page:"",
page_1:"page1",
page_2:"page2",
page_3:"page3",
page_4:"page4",
items:['page1','page2','page3','page4'],
nextNum: 10
}
},
methods: {
randomIndex: function () {
return Math.floor(Math.random() * this.items.length)
},
add: function () {
this.items.splice(this.randomIndex(), 0, "page"+this.nextNum++)
},
remove: function () {
this.items.splice(this.randomIndex(), 1)
},
clicked(item){
const index=this.items.indexOf(item);
if(index==0){
if(this.page==item)
...