Configuring the Mobile Viewport
When developing web applications for mobile devices, it is crucial to prevent unintended user scaling to maintain a consistent UI. This is achieved by configuring the viewport meta tag in the HTML head.
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
Additional, setting up a responsive foundation using rem units requires defining a base font size on the root element. By setting the root font size to 100px, component styling becomes straightforward (e.g., 0.16rem equals 16px).
html {
font-size: 100px;
height: 100%;
}
body {
height: 100%;
margin: 0;
font-size: 0.16rem;
}
Injecting Dynamic Routes
In Vue Router, routes fetched asynchronously must be injected into the router instance both after a successful login and when the application reloads to persist navigation state.
Route Injection on Authentication
After validating user credentials, parse the asynchronous route configuration to resolve component paths, persist the authentication token, and append the routes dynamically.
const asyncNavConfig = await fetchRouteDefinitions();
asyncNavConfig.forEach(routeDef => {
const componentPath = routeDef.componentPath;
routeDef.component = (resolve) => require([`@/views/${componentPath}`], resolve);
});
window.sessionStorage.setItem('authToken', 'user_token_value');
this.$router.addRoutes(asyncNavConfig);
Route Restoration on Page Refresh
To ansure dynamically added routes survive a browser refresh, the router configuraton file must check for an existing token and re-inject the routes before the application mounts.
if (window.sessionStorage.getItem('authToken')) {
const dynamicRoutes = await fetchRouteDefinitions();
dynamicRoutes.forEach(routeDef => {
const componentPath = routeDef.componentPath;
routeDef.component = (resolve) => require([`@/views/${componentPath}`], resolve);
});
router.addRoutes(dynamicRoutes);
}
Hydrating Vuex State on Refresh
Vuex state resets when the page reloads. To hydrate the store with necessary data, use the beforeEach navigation guard to await state restoration before resolving the route.
import Vue from 'vue';
import Router from 'vue-router';
import HomeView from '@/views/HomeView';
import store from '@/store';
Vue.use(Router);
const router = new Router({
routes: [
{ path: '/', redirect: '/home' },
{ name: 'HomeView', path: '/home', component: HomeView }
]
});
if (window.sessionStorage.getItem('authToken')) {
setTimeout(() => { // Simulating asynchronous route fetch
const fetchedRoutes = getAsyncRoutes();
fetchedRoutes.forEach(r => {
r.component = (resolve) => require([`@/views/${r.componentPath}`], resolve);
});
router.addRoutes(fetchedRoutes);
}, 1000);
}
router.beforeEach(async (to, from, next) => {
if (window.sessionStorage.getItem('authToken')) {
await new Promise(resolve => {
setTimeout(() => { // Simulating asynchronous state fetch
const statePayload = retrieveStorePayload();
store.commit('hydrateState', statePayload);
resolve();
}, 500);
});
}
next();
});
export default router;
Handling Unauthorized API Responses
Configure Axios interceptors to monitor API responses. If an authentication failure or session expiration is detected, automatically redirect the user back to the login interface.
import Vue from "vue";
import Axios from "axios";
import router from "@/router";
Axios.interceptors.request.use(
config => config,
error => Promise.reject(error)
);
Axios.interceptors.response.use(
response => {
if (response.data.authError) {
if (router.currentRoute.path !== "/auth/login") {
router.push({ name: "LoginView" });
}
}
return response;
},
error => {
if (router.currentRoute.path !== "/auth/login") {
router.push({ name: "LoginView" });
}
return Promise.reject(error);
}
);
Vue.prototype.$axios = Axios;