Vue.js page transition fade effect with vue-router - transition

How to achieve a fade effect page transition between vue-router defined pages (components)?

Wrap <router-view></router-view> with <transition name="fade"></transition> and add these styles:
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
Detailed answer
Assuming you have created your application with vue-cli, e.g.:
vue init webpack fadetransition
cd fadetransition
npm install
Install the router:
npm i vue-router
If you are not developing your app using vue-cli, make sure to add the vue router the standard way:
<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>
You can use e.g.: https://unpkg.com/vue-router/dist/vue-router.js
The CLI has created a backbone application for you, which you can add components to.
1) Create page components
In Vue, components (UI elements) can be nested. A page in your app can be made with a regular Vue component that is considered as the root to other components in that page.
Go to src/ and create pages/ directory. These page-root components (individual pages) will be put in this directory, while the other components used in the actual pages can be put to the ready-made components/ directory.
Create two pages in files called src/pages/Page1.vue and src/pages/Page2.vue for starters. Their content will be (edit page numbers respectively):
<template>
<h1>Page 1</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
2) Setup routing
Edit the generated src/main.js add the required imports:
import VueRouter from 'vue-router'
import Page1 from './pages/Page1'
import Page2 from './pages/Page2'
Add a global router usage:
Vue.use(VueRouter)
Add a router setup:
const router = new VueRouter({
routes: [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 },
{ path: '/', redirect: '/page1' }
]
})
The last route just redirects the initial path / to /page1. Edit the app initiation:
new Vue({
router,
el: '#app',
render: h => h(App)
})
The whole src/main.js example is at the end of the answer.
3) Add a router view
Routing is set up by now, just a place where the page components will be rendered according to the router is missing. This is done by placing <router-view></router-view> somewhere in the templates, you will want to put it in the src/App.vue's <template> tag.
The whole src/App.vue example is at the end of the answer.
4) Add fade transition effect between page components
Wrap the <router-view></router-view> with a <transition name="fade"> element, e.g.:
<template>
<div id="app">
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</template>
Vue will do the job here: it will create and insert appropriate CSS classes starting with the name specified through-out the effect's duration, e.g.: .fade-enter-active. Now define the effects in App.vue's section:
<style>
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
</style>
That's it. If you run the app now, e.g. with npm run dev, it will automatically display Page 1 with a fade-in effect. If you rewrite the URL to /page2, it will switch the pages with fade-out and fade-in effects.
Check out the documentation on routing and transitions for more information.
5) Optional: Add links to pages.
You can add links to particular pages with the <router-link> component, e.g.:
<router-link to="/page1">Page 1</router-link>
<router-link to="/page2">Page 2</router-link>
This automatically gives the links a router-link-active class in case they are active, but you can also specify custom classes if you are using e.g. Bootstrap:
<router-link class="nav-link" active-class="active" to="/page1">Page 1</router-link>
<router-link class="nav-link" active-class="active" to="/page2">Page 2</router-link>
Files for reference
src/main.js:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import Page1 from './pages/Page1'
import Page2 from './pages/Page2'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 },
{ path: '/', redirect: '/page1' }
]
})
/* eslint-disable no-new */
new Vue({
router,
el: '#app',
render: h => h(App)
})
src/App.vue:
<template>
<div id="app">
<router-link class="nav-link" active-class="active" to="/page1">Page 1</router-link>
<router-link class="nav-link" active-class="active" to="/page2">Page 2</router-link>
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style>
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
</style>
src/pages/Page1.vue:
<template>
<h1>Page 1</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
src/pages/Page2.vue:
<template>
<h1>Page 2</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>

Plug and Play Solution
There is also a plug and play solution called vue-page-transition which offers you all sort of transitions. (fade, flip, zoom, overlay etc.)
1 - Install the npm package:
yarn add vue-page-transition
2 - register the plugin:
import Vue from 'vue'
import VuePageTransition from 'vue-page-transition'
Vue.use(VuePageTransition)
3 - wrap your router-view with the global animation:
<vue-page-transition name="fade-in-right">
<router-view/>
</vue-page-transition>
Learn more on GitHub:
https://github.com/Orlandster/vue-page-transition

Related

Layer control using leaftejs and vuejs

Everyone I am a junior developer at NESAC(ISRO).
I am working on a project with vue JS and leaflet JS. So my task is:-
Using Leaflet JS, I have to render a map on the screen.
Set markers at "n" specific locations on the renderd map.
Create a sidebar with a checkbox of various entities such as cities, restaurants, parks etc.
Develop a Vue app such that, I create my different components on the components folder, so that all my components go through App.vue file and gets renderd at the index.html, i.e. my browser.
And, now I have to make a Layer control function such that each of my entities gets different reactions. Eg. If I click the restaurant checkbox at the sidebar, then all my restaurant leaflet markers should be shown on the screen, but each entity should have different reactivity.
Github Link.
You can use npm package for that - Vue2Leaflet
Here is docu: https://vue2-leaflet.netlify.app
And simple Map with Vue.js and leaflet:
<template>
<div style="height: 350px;">
<div class="info" style="height: 15%">
<span>Center: {{ center }}</span>
<span>Zoom: {{ zoom }}</span>
<span>Bounds: {{ bounds }}</span>
</div>
<l-map
style="height: 80%; width: 100%"
:zoom="zoom"
:center="center"
#update:zoom="zoomUpdated"
#update:center="centerUpdated"
#update:bounds="boundsUpdated"
>
<l-tile-layer :url="url"></l-tile-layer>
</l-map>
</div>
</template>
<script>
import {LMap, LTileLayer} from 'vue2-leaflet';
export default {
components: {
LMap,
LTileLayer,
},
data () {
return {
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
zoom: 3,
center: [47.413220, -1.219482],
bounds: null
};
},
methods: {
zoomUpdated (zoom) {
this.zoom = zoom;
},
centerUpdated (center) {
this.center = center;
},
boundsUpdated (bounds) {
this.bounds = bounds;
}
}
}
</script>
It's just a wrapper for a leaflet and you have complete access to all the leaflet functions through:
mounted() {
this.$nextTick(() => {
this.map = this.$refs.map.mapObject;
});
}
I think that can be a good start for you.

How I can use my jquery plugin in Next.js?

i'm developing web app using Next.js and I'd like to use jQuery in Next.js.
But I can't import jquery plugin.
please check my code and Help me.
import React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
const sheet = new ServerStyleSheet();
const page = renderPage(App => props => sheet.collectStyles(<App {...props} />));
const styleTags = sheet.getStyleElement();
return { ...page, styleTags };
}
render() {
return (
<html lang="en">
<Head>{this.props.styleTags}
<link
href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0/katex.min.css"
rel="stylesheet"
/>
<script src="../static/js/jquery.main.js" async/>
</Head>
<body>
<Main />
<div id="modal" />
<NextScript />
</body>
</html>
);
}
}
One typical issue you will get into if you do jQuery is, After importing the jQuery plugins they will register for onClick events, and by that time you can't guarantee that the actual DOM Element is ready, elements may get created later and may get refreshed.
One way of solving the issues is call the jQuery code which does the initialization in componentDidMount() and also in componentDidUpdate() so that you can make sure the DOM elements are present before the jQuery plugin register them.

Polymer: How to store REST API base URL in configuration file

I'm using polymer starter kit.I have to make many API calls in different HTML pages and for each API call, I'm using "iron-ajax" in that for 'url' property I'm assigning REST API URL.
URL will be like "https://XXXXX.in/YY/YY/YY" ,Here base URL XXXXX is same for all API call and YY will change.So how can I store Base URL XXX in one configuration file and access that value in all the pages for all "iron-ajax"? where I should access Base URL, is it inside polymer's 'ready' function for all the pages?
OPTION 1
In Polymer you would store values as properties. If you have the base URL as a property on top of the node tree (in the first parent element), you can pass it on to any child element (and then they can pass it further down).
Your top element:
<link rel="import" href="./child-el.html">
<dom-module id="main-el">
<template>
<child-el base-url="[[baseUrl]]"></child-el>
</template>
</dom-module>
<script>
Polymer({
is: 'main-el',
properties: {
baseUrl: {
type: String,
value: 'https://XXXXX.in'
}
}
});
</script>
The child:
<dom-module id="child-el">
<template>
<iron-ajax url="[[baseUrl]]/YY/YY/YY"></iron-ajax>
</template>
</dom-module>
<script>
Polymer({
is: 'child-el',
properties: {
baseUrl: {
type: String
}
}
});
</script>
OPTION 2
You can put all ajax calls in one element that doesn't render anything on the screen and include that element anywhere you need.
<link rel="import" href="./api-handler.html">
<dom-module id="main-el">
<template>
<api-handler id="api-handler"></api-handler>
</template>
</dom-module>
<script>
Polymer({
is: 'main-el',
attached () {
this.$['api-handler'].makeRequest();
}
});
</script>
OPTION 3
Store the baseUrl property in a Polymer behavior and include that in your elements.
OPTION 4
You can attach the value to the globally accessible window object. Your config.html would look like:
<script>
(function (Config) {
Config.BASE_URL = 'https://XXXXX.in';
})(window.Config = window.Config || {});
</script>
Then you import that in your index.html:
<link rel="import" href="./config.html">
..and Config.BASE_URL will be available in all your elements.

How to handle events using Electron + Vue (SPA)

I am having problems figuring out how to handle events when using Vue together with Electron. It may seem stupid, but I have spent time reading the docs, testing Vue instances and directives in the browser which works fine but the same principles won't work in my electron desktop app (this is so much different then Php OOP).
I use the electron-vue boilerplate, set it up, works like a charm. Created a template and a component (TopMenu), now I need to handle the click event of the menu buttons placed into my TopMenu component, but no matter how I try, I get:
[Vue warn]: Property or method "say" is not
defined on the instance but referenced during render. Make sure to
declare reactive data properties in the data option. (found in
component )
[Vue warn]: Handler for event "click" is undefined.
./LandingPageView/TopMenu.vue:
<template>
<div>
<button type="button" name="button" v-on:click="say">BUTTON</button>
</div>
</template>
main.js:
import Vue from 'vue'
import Electron from 'vue-electron'
import Resource from 'vue-resource'
import Router from 'vue-router'
import App from './App'
import routes from './routes'
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.min.js'
Vue.use(Electron)
Vue.use(Resource)
Vue.use(Router)
Vue.config.debug = true
const router = new Router({
scrollBehavior: () => ({ y: 0 }),
routes
})
/* eslint-disable no-new */
new Vue({
methods: {
say: function () {
alert()
}
},
router,
...App
}).$mount('#app')
App.vue:
<style>
#import url(https://fonts.googleapis.com/css?family=Lato:400,700);
* {
margin: 0;
padding: 0;
}
html,
body { height: 100%; }
body {
align-items: center;
background:
radial-gradient(
ellipse at center,
rgba(255, 255, 255, 1) 0%,
rgba(229, 229, 229, .85) 100%
);
background-position: center;
font-family: Lato, Helvetica, sans-serif;
}
</style>
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
import store from 'src/vuex/store'
export default {
store
}
</script>
index.ejs:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
<!-- webpack builds are automatically injected -->
</body>
</html>
Hello you need to put the methods in the same component that the template:
<template>
<div class="example" #click="say">say method</div>
</template>
<script>
export default {
methods: {
say () {
console.log('Hello world!')
}
}
}
</script>
Take a look in the vue documents: https://v2.vuejs.org/v2/guide/

Ionic - Showing side-menu ONLY in concrete pages

I'm developing an App with Ionic Framework, and I only want to show a side-menu in some concrete views, but not in every view.
I' have my menu.html file:
<ion-side-menus>
<ion-pane ion-side-menu-content>
<ion-nav-bar class="bar-positive nav-title-slide-ios7">
</ion-nav-bar>
<ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view>
</ion-pane>
<ion-side-menu side="left">
<ion-content class="mymenu">
<div id="menu-list">
<ion-list class="list">
<ion-item item-type="item-icon-left" nav-clear menu-close href="#">
<i class="icon ion-home"></i><span>Menu Item</span>
</ion-item>
...
</ion-list>
</div>
</ion-content>
</ion-side-menu>
</ion-side-menus>
My index.html's body tag looks exactly like this:
<body ng-app="myApp">
<ion-nav-view></ion-nav-view>
</body>
And the JavaScript code where I set up my App states:
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl'
})
.state('app.page1', {
url: "/page1",
views: {
'menuContent' :{
templateUrl: "templates/page1.html"
}
}
})
.state('app.page2', {
url: "/page2",
views: {
'menuContent' :{
templateUrl: "templates/page2.html"
}
}
})
// etc...
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/page1');
});
page1.html and page2.html both contain the following structure:
<ion-view title="something">
<ion-content>
... // here comes the html content of the page
</ion-content>
</ion-view>
What can I actually do to only show my side-menu (menu.html) on page1.html and not on page2.html?? Is there anything I'm missing??
Is there a way of inserting the menu.html content only on those pages I want it to appear and forgetting about creating the state that uses it as templateUrl?
The reason why your all your pages have side menu is because you 'app' state as their parent state. When a state is activated, its templates are automatically inserted into the <ion-view> of its parent state's template. If it's a top-level state, because it has no parent state then its parent template is index.html. The app state has the side menu in it.
Your code should look like this:
config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl'
})
//this state has the 'app' state (which has the sidemenu) as its parent state
.state('app.page1', {
url: "/page1",
views: {
'menuContent' :{
templateUrl: "templates/page1.html"
}
}
})
//this state has no parent, so it uses 'index.html' as its template. The index page has no
//sidemenu in it
.state('page2', {
url: "/page2",
templateUrl: "templates/page2.html"
}
})
///more code here
});
Check out https://github.com/angular-ui/ui-router/wiki
if your problem is simple , use
onExit: function(){
angular.element(document.querySelector('#menuAPP')).removeClass('hidden');
}
into state
just add hide-nav-bar=" true " in ion-view
<ion-view title="Login" **hide-nav-bar="true"** id="page" class=" "> </ion-view>