I'm trying to code simple slide panel, like here http://anton.shevchuk.name/wp-demo/jquery-tutorials/simple-slide-panel.html
but on Vue.js. But panel doesn't slide it's wait 2 seconds then close without animation.
https://codepen.io/TogusaRusso/pen/dqoMLr
If I remove v-if, I can animate it, changing height of div.
https://codepen.io/TogusaRusso/pen/mGJEEJ
How can I animate removing of div?
<template>
<v-flex xs12 sm6 offset-sm3>
<transition name="slide" :duration="2000">
<div
class="slide-media"
:style="{height: '400px'}"
v-if="isOpen"
>Hello!</div>
</transition>
<v-btn
flat color="orange"
#click="isOpen=!isOpen"
>
{{isOpen?"Close":"Open"}}
</v-btn>
</v-flex>
</template>
<script>
export default {
name: 'SlidePanel',
data() {
return {
isOpen: false,
}
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.slide-media {
background-color: orangered;
overflow-y:hidden;
}
.slide-enter-active, .slide-leave-active {
transition: height 2s;
}
.slide-enter, .slide-leave-to {
height: 0px;
}
</style>
Check MDN: Css Specificity,
Inline styles added to an element (e.g., style="font-weight:bold")
always overwrite any styles in external stylesheets, and thus can be
thought of as having the highest specificity.
So removed the inline styles :style="{height: '400px'}", then add height:400px; inside .slide-media.
Below is one demo:
new Vue({
el: '#app',
data(){
return {
isOpen: false
}
},
methods: {
togglePanel: function () {
this.isOpen = !this.isOpen
}
}
})
.slide-media {
background-color: orangered;
overflow-y:hidden;
height:400px;
}
.slide-enter-active, .slide-leave-active {
transition: height 2s;
}
.slide-enter, .slide-leave-to {
height: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<button #click="togglePanel()">Toggle Panel</button>
<transition name="slide" :duration="2000">
<div
class="slide-media"
v-if="isOpen"
>Hello!</div>
</transition>
</div>
Related
It is my first time to work with Vue or Web. I have been to working with C to write firmware.
Depends on sidebar state, I would like to change padding-right value of body in App.vue.
whenever button is pushed, isNavOpen value is changed
import Vue from "vue";
export const store = Vue.observable({
isNavOpen: false
});
export const getters = {
getNavOpen: () => store.isNavOpen
}
export const mutations = {
setIsNavOpen(yesno) {
store.isNavOpen = yesno;
},
toggleNav() {
store.isNavOpen = !store.isNavOpen;
}
};
so I would like to change padding-right value of body in App.vue
<template>
<div id="app">
<nav class="main-nav">
<div class="logo">my.company</div>
<Burger></Burger>
</nav>
<Sidebar>
<ul class="sidebar-panel-nav">
<li>
Home
</li>
<li>
About
</li>
<li>
Contact
</li>
</ul>
</Sidebar>
<router-view />
</div>
</template>
<script>
import Burger from "./components/Menu/Burger.vue";
import Sidebar from "./components/Menu/Sidebar.vue";
import { store, getters, mutations } from '#/store.js'
export default {
name: "app",
components: {
Burger,
Sidebar
},
data:{
return: {
isSidebarOpen: this.$getters.getNavOpen()
}
}
};
</script>
<style>
html {
height: 100%;
overflow: hidden;
}
body {
border: 0;
margin: 0;
padding-left: 350px;
font-family: "Lato";
height: 100%;
background: rgb(101, 31, 87);
background: linear-gradient(
45deg,
rgba(101, 31, 87, 1) 0%,
rgba(225, 113, 87, 1) 48%,
rgba(249, 248, 113, 1) 100%
);
}
</style>
I read pages. However it is so hard to combine these codes for me
change style
vue sidebar tutorial
or Is any way to implmement to change padding by sidebar states?
Some thing might be missing in your second block but i assume that you successfully can use true or false value as isSideBarOpen. All you need to do is to use style binding(you can also use class binding but you need to define specific class for padding right) Here is what you need:
<div id="app" :style="(isSideBarOpen) ? 'padding-right: 10px;' : ''">
/* code */
</div>
I am trying to create a splash screen (loading-screen) in Vue JS that after a few seconds fades away, revealing my defaut view. I have tried several approaches but just can't get any to work. The closest is this example on CodePen But ideally the component wouldn't be inside main.js and instead inside its own component. Despite that the below code won't work.
My main.js is as below:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
Vue.config.productionTip = false;
// FILTERS
Vue.filter('snippet', function(value) {
return value.slice(0,100);
});
Vue.component('loading-screen', {
template: '<div id="loading">Loading...</div>'
})
new Vue({
router,
store,
render: h => h(App),
data: {
isLoading: true
},
mounted () {
setTimeout(() => {
this.isLoading = false
}, 3000)
}
}).$mount("#app");
and my App.vue is as follows
<template>
<div id="app">
<loading-screen v-if="isLoading"></loading-screen>
<Top/>
<router-view/>
<PrimaryAppNav/>
</div>
</template>
<script>
import Top from './components/Top.vue'
import PrimaryAppNav from './components/PrimaryAppNav.vue'
export default {
name: 'app',
components: {
Top,
PrimaryAppNav
}
}
</script>
A LoadingScreen.vue component could look like this:
<template>
<div :class="{ loader: true, fadeout: !isLoading }">
Loading ...
</div>
</template>
<script>
export default {
name: "LoadingScreen",
props: ["isLoading"]
};
</script>
<style>
.loader {
background-color: #63ab97;
bottom: 0;
color: white;
display: block;
font-size: 32px;
left: 0;
overflow: hidden;
padding-top: 10vh;
position: fixed;
right: 0;
text-align: center;
top: 0;
}
.fadeout {
animation: fadeout 2s forwards;
}
#keyframes fadeout {
to {
opacity: 0;
visibility: hidden;
}
}
</style>
Be aware that the loader needs to be aware if loading is done to be able to fade out. You need to check that in your App as well, so it's not showing while it still needs to prepare data. Otherwise, information from the app part in the background could be leaking (for example scrollbars might be visible on the LoadingScreen). So App.vue could have a template like this:
<template>
<div id="app">
<LoadingScreen :isLoading="isLoading" />
<div v-if="!isLoading">
...your main content here...
</div>
</div>
</template>
If you want to have the LoadingScreen divs to disappear completely, you need to manage the state of the fadeout animation in the App.vue itself, making it a bit more complicated (I'd probably use two props for LoadingScreen then: isLoading and fadeout, where fadeout is a callback that gets called in LoadingScreen as soon as the fadeout animation is complete).
I have prepared a codesandbox for you with the state management inside the LoadingScreen.
This is a working App.vue with a splash screen:
<template>
<div id="app">
<v-app :light="!nav.dark" :dark="nav.dark">
<transition name="slide-fade" mode="out-in">
<router-view></router-view>
</transition>
</v-app>
<div v-if="loading" style="position:absolute; width: 100%; height:100%; top:0; left:0; z-index:10000; background-color:white">
<div style="margin-left: auto; margin-right: auto">
Loading...
</div>
</div>
</div>
</template>
<script>
export default {
name: "app",
data: () => ({
loading: true
}),
mounted() {
setTimeout(() => {
this.loading = false
}, 3000)
}
}
</script>
Note that there is a z-index trick and mounted is in App component.
You can of course create a component just for loading, so it will become:
App.vue
<template>
<div id="app">
<v-app :light="!nav.dark" :dark="nav.dark">
<transition name="slide-fade" mode="out-in">
<router-view></router-view>
</transition>
</v-app>
<loader v-if="loading"/>
</div>
</template>
<script>
import Loader from "./Loader"
export default {
name: "app",
data: () => ({
loading: true
}),
mounted() {
setTimeout(() => {
this.loading = false
}, 3000)
}
}
</script>
Loader.vue
<template>
<div style="position:absolute; width: 100%; height:100%; top:0; left:0; z-index:10000; background-color:white">
<div style="margin-left: auto; margin-right: auto">
Loading...
</div>
</div>
</template>
<script>
export default {
name: "loader"
}
</script>
After that, I strongly suggest that you use dynamic components for your router components, Top and PrimaryAppNav. Like that they will load during your splash screen. You will find how to do that very easily in my answer in this thread (only section 2 is relevant for you): here
At beginning show fullscreen splash (with class binding listens for loadedApp).
When vuejs mounted, (or your any other process completed then, change data loadedApp = true.
Then fadeoutHide style will run and hides your splash
<div class="fullscreen-splash" :class="{fadeoutHide:loadedApp}">
// splash logo etc
</div>
data() {
return {
loadedApp: false
}
},
mounted() {
this.loadedApp = true
}
.fadeoutHide {
animation: fadeoutHide .5s forwards;
}
#keyframes fadeoutHide {
to {
opacity: 0;
visibility: hidden;
}
}
I'm trying to get different components into tabs content here https://codepen.io/iTaurus85/pen/KbrBEa
When switching tabs I need to get the content from those components. BUt I just get a text.
How can I solve this problem? Or maybe I have chosen the wrong way to show different pages via tabs?
<div id="app">
<v-content>
<v-layout row wrap class="tab-layout">
<v-toolbar color="cyan" dark tabs>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title>Page title</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon>
<v-icon>search</v-icon>
</v-btn>
<v-btn icon>
<v-icon>more_vert</v-icon>
</v-btn>
<v-tabs
slot="extension"
v-model="tab"
color="cyan"
align-with-title
>
<v-tabs-slider color="yellow"></v-tabs-slider>
<v-tab v-for="item in levels" :key="item">
{{ item.name }}
</v-tab>
</v-tabs>
</v-toolbar>
<v-tabs-items v-model="tab">
<v-tab-item v-for="item in levels" :key="item">
<v-card flat>
{{ item.content }}
</v-card>
</v-tab-item>
</v-tabs-items>
</v-layout>
</v-content>
</div>
new Vue({
el: '#app',
// components:{
// intro,
// Elementary,
// },
data () {
return {
tab: null,
levels: [
{name:'Beginner', content: '<intro></intro>'},
{name:'Elementary', content: '<elementary></elementary>'},
{name:'Pre-Intermediate', content: 'Pre-Intermediate'},
{name:'Intermediate', content: 'Intermediate'},
{name:'Upper-Intermediate', content: 'Upper-Intermediate'}
]
}
}
})
The answer is here https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components.
This example https://jsfiddle.net/chrisvfritz/o3nycadu/ showed exactly what I wanted.
<script src="https://unpkg.com/vue"></script>
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
v-bind:key="tab"
v-bind:class="['tab-button', { active: currentTab === tab }]"
v-on:click="currentTab = tab"
>{{ tab }}</button>
<component
v-bind:is="currentTabComponent"
class="tab"
></component>
</div>
Vue.component('tab-home', {
template: '<div>Home component</div>'
})
Vue.component('tab-posts', {
template: '<div>Posts component</div>'
})
Vue.component('tab-archive', {
template: '<div>Archive component</div>'
})
new Vue({
el: '#dynamic-component-demo',
data: {
currentTab: 'Home',
tabs: ['Home', 'Posts', 'Archive']
},
computed: {
currentTabComponent: function () {
return 'tab-' + this.currentTab.toLowerCase()
}
}
})
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.tab-button.active {
background: #e0e0e0;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
You can use v-html directive: https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML - codepen: https://codepen.io/anon/pen/EGOOym.
But a better approach would be create separate components for each tab.
You can use is (Vue :is) for your v-for + components for each tab:
<div v-for="item in items"><component :is="item.componentName"></component></div>
Your item can be something like:
{componentName: 'Intermidiate', tasks: 100}
And in a Vue instance you should also add component like:
new Vuew({
components: {
Inetrmidiate,
}
})
And the last point - just create new Vue-component named Intermidiate.
jsffidle
<div class="container">
<input placeholder="find PLEASE" v-model="search" />
<transition-group name="fade">
<div v-for="(item, index) in filteredItems" :key="index" class="container__item">{{ item }}</div>
.container {
display: flex;
flex-wrap: wrap;
flex-direction: column;
}
new Vue({
el: '.container',
data() {
return {
search: '',
items: ['lorem opas', 'opas loram ', 'mushroms so good']
}
},
computed: {
filteredItems() {
return this.items.filter(item => item.indexOf(this.search) > -1)
}
}
})
Why transition-group animation not worked? all items have a unique key, also I get the name for transition-group.
Your transition is in fact working, however you haven't specified any style for it.
From the official documentation:
When an element wrapped in a transition component is inserted or
removed, this is what happens:
Vue will automatically sniff whether the target element has CSS
transitions or animations applied. If it does, CSS transition classes
will be added/removed at appropriate timings.
To make your example work, you can have like so:
new Vue({
el: '.container',
data() {
return {
search: '',
items: [
'lorem opas',
'opas loram ',
'mushroms so good'
]
}
},
computed: {
filteredItems() {
return this.items.filter(item =>
item.indexOf(this.search) > -1
)
}
}
})
.container {
display: flex;
flex-wrap: wrap;
flex-direction: column;
}
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div class="container">
<input placeholder="find PLEASE" v-model="search" />
<transition-group name="fade">
<div class="container__item"
v-for="(item, index) in filteredItems"
:key="index"
>
{{ item }}
</div>
</transition-group>
</div>
All that was missing were the CSS transition classes.
<transition-group name="fade">
In this case, the specified name should be the prefix of all the css classes. Currently there are 6 transition classes that vue uses, which for the example above, would be the following:
fade-enter
fade-enter-active
fade-enter-to
fade-leave
fade-leave-active
fade-leave-to
Also note that you can share the same classes with multiple instances of this transition-group in your app.
I have a spa vue page with vuetify, and when I change between the components of the aplication I want the component shows with a transition.
I tried with the <v-slide-y-transition> tag and the transition="slide-y-transition attribute but nothing works. Here some examples of what I tried:
Example with the "vuetify tag":
<template>
<v-app>
<v-slide-y-transition>
<h1>Test</h1>
</v-slide-y-transition>
</v-app>
</template>
Example with the attribute:
<template>
<v-app>
<div transition="slide-y-transition">
<h1>Test</h1>
</div>
</v-app>
</template>
The Vuetify transitions as you have them only work on the Vuetify library components. e.g. <v-menu transition="slide-x-transition"> where v-menu is one of the components. You can't use the transitions that way on a simple <div>.
However, Vue.js itself supports transitions using the following format.
<transition name="slide">
<div> element you are apply the transition to</div>
</transition>
You will have to define the css for the transition as per the documentation here. or you can use a css library like Animate.css
Example css from documentation:
.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 {
transform: translateX(10px);
opacity: 0;
}
In case someone needs to know how to use VuetifyJS transitions with router-view which I understood by page transitions.
Vuetify router-view Transitions
Vue2 / Vuetify2
Here you can use the Vuetify transitions directly
<v-main>
<v-container fill-height>
<v-slide-x-transition mode="out-in">
<router-view />
</v-slide-x-transition>
</v-container>
</v-main>
Vue3 / Vuetify3
In Vue3 / Vuetify3 this is unfortunately no longer directly usable due to the changes in the router-view API. But of course you can pick the values of the Vuetify transitions on Github and recreate them accordingly.
<template>
<v-main>
<v-container fill-height>
<router-view v-slot="{ Component, route }">
<transition name="slide-x" mode="out-in">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</v-container>
</v-main>
</template>
<style>
/* v-slide-x-transition look a like */
.slide-x-enter-active,
.slide-x-leave-active {
transition: transform .6s cubic-bezier(0.25, 0.8, 0.5, 1), opacity .8s;
opacity: 1;
}
.slide-x-enter-from,
.slide-x-leave-to {
opacity: 0;
}
.slide-x-enter-from {
transform: translateX(100px);
}
.slide-x-leave-to {
transform: translateX(-100px);
}
</style>
You can use Vuejs transition For changing components instead of vuetify transitions look at the following example:
<transition name="slide-in-down" appear appear-active-class="animated slideInDown">
<div> element you are apply the transition to</div>
</transition>