blog.atakanonol.dev

Developing mobile-friendly web applications can be a challenging task, especially when you need to adapt the layout and design for smaller screens. In this blog post, I’ll walk you through the process of creating a Vue.js application and implementing mobile-friendly navigation menus using Vue Router.

I partly followed John Komarnicki’s Youtube tutorial and this tutorial showing how to set up Vue router. You may also check out my own repository here.

Getting Started: Creating a Vue Project

To start, let’s create a Vue project using vue-cli. Open your terminal and run the following command to generate a new project folder:

vue create project-name

This command will set up the basic project structure and install the necessary dependencies.

 
 

 

 

Adding Vue Router

For effective navigation and routing in your Vue application, Vue Router is a must. It’s a good practice to add Vue Router at the beginning of your project. In the project directory, execute the following command to add Vue Router:

vue add router

When prompted, select “yes” to use history mode for cleaner URLs.

Upon successful installation, you’ll notice several new files and folders in your project. The views folder will contain the pages you can navigate to, while the router folder contains the crucial index.js file responsible for routing.

Here’s an example of an index.js file for Vue Router:

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    path: '/blog',
    name: 'blog',
    beforeEnter() {window.location.href = 'https://blog.atakanonol.dev'}
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

The routes object defines the paths and corresponding Vue components. You can also use the beforeEnter guard to redirect to external URLs, as shown in the example.

Creating a Mobile-Friendly Navbar

Designing a mobile-friendly navigation menu can be challenging, but it’s crucial for providing a smooth user experience on smaller screens. Below is a Vue component for a mobile-friendly navigation bar:

 
<template>
    <header :class="{ 'scrolled-nav': scrolledNav }">
        <nav>
            <div class="branding">
                <img @click="navigateTo('/')" src="@/assets/logo.png" alt="" />
            </div>
            <ul v-show="!mobile" class="navigation">
                <li><router-link class="link" to="/">Home</router-link></li>
                <li><router-link class="link" to="/blog">Blog</router-link></li>
                <li><router-link class="link" to="/about">About</router-link></li>
            </ul>
            <div class="icon" @click="toggleMobileNav" v-show="mobile" :class="{ 'icon-active': mobileNav }">
                <font-awesome-icon :icon="['fas', 'bars']" />
            </div>
            <transition name="mobile-nav">
                <ul v-show="mobileNav" class="dropdown-nav">
                    <li><router-link class="link" to="/">Home</router-link></li>
                    <li><router-link class="link" to="/about">About</router-link></li>
            </ul>
            </transition>
        </nav>
    </header>
    <router-view/>
</template>

<script>
export default {
    name: "NavigationBar",
    data() {
        return {
            scrolledNav: null,
            mobile: null,
            mobileNav: null,
            windowWidth: null
        }
    },
    created() {
        window.addEventListener("resize", this.checkScreen)
        this.checkScreen()
    },
    mounted() {
        window.addEventListener("scroll", this.updateScroll)
    },
    methods: {
        navigateTo (page) {
            if (page.startsWith('/')) {
                this.$router.push(page)    
            } else {
                window.location.href(page)
            }
        },
        toggleMobileNav () {
            this.mobileNav = !this.mobileNav
        },
        checkScreen () {
            this.windowWidth = window.innerWidth
            if (this.windowWidth <= 750) {
                this.mobile = true
                return
            }
            this.mobile = false
            this.mobileNav = false
        },
        updateScroll () {
            const scrollPosition = window.scrollY
            if (scrollPosition > 50) {
                this.scrollNav = true
                return
            }
            this.scrollNav = false
        }
    }
}
</script>

<style lang="scss" scoped>
header {
    background-color: rgba(255, 255, 255);
    z-index: 99;
    width: 100%;
    position: fixed;
    top: 0px;
    left: 0px;
    transition: .5s ease all;
    box-shadow: 0px 2px #ff851b6c;


    nav {
        position: relative;
        display: flex;
        flex-direction: row;
        padding: 0;
        transition: .5s ease all;
        height: 5vh;
        min-height: 50px;
        width: 90%;
        margin: 0 auto;
        @media (min-width: 1140px) {
            max-width: 1140px;
        }

        ul,
        .link {
            font-weight: 500;
            color: #001f3f;
            list-style: none;
            text-decoration: none;
        }

        li {
            text-transform: uppercase;
            padding: 16px;
            margin-left: 16px;
        }

        .link {
            font-size: 14px;
            transition: .5s ease all;
            padding-bottom: 4px;
            border-bottom: 1px solid transparent;

            &:hover {
                color: #ff851b;
                border-color: #ff851b;
            }
        }

        .branding {
            display: flex;
            align-items: center;

            img {
                max-height: 50px;
                transition: .5s ease all;

                &:hover {
                    cursor: pointer;
                }
            }
        }

        .navigation {
            display: flex;
            align-items: center;
            flex: 1;
            justify-content: flex-end;
        }

        .icon {
            display: flex;
            align-items: center;
            position: absolute;
            top: 0px;
            right: 24px;
            height: 100%;
            cursor: pointer;
            font-size: 24px;
            transition: .8s ease all;
            color: #001f3f;
        }

        .icon-active {
            transform: rotate(180deg);
        }

        .dropdown-nav {
            display: flex;
            flex-direction: column;
            position: fixed;
            width: 100%;
            max-width: 250px;
            height: 100%;
            background-color: #fff;
            top: 0px;
            left: 0px;
            margin-top: 0px;
            padding-top: 20px;
            padding-left: 0px;

            li {
                margin-left: 0px;
                text-align: left;
                .link {
                    color: #000;
                }
            }
        }

        .mobile-nav-enter-active,
        .mobile-nav-leave-active {
            transition: .8s ease all;
        }

        .mobile-nav-enter-from,
        .mobile-nav-leave-to {
            transform: translateX(-250px);
        }

        .mobile-nav-enter-to {
            transform: translateX(0);
        }
    }
}

.scrolled-nav {
    background-color: #000;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);

    nav {
        padding: 8px 0;

        .branding {
            img {
                box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
            }
        }
    }
}
</style>

I highly recommend checking out the tutorial for much more detailed explainations. In this component, we have a navigation bar that adapts to screen size changes. It includes a hamburger menu for mobile users and a dropdown menu for desktop users when hovering over the “Home” link. Additionally, clicking on the logo navigates the user to the home page. Once I also get the dropdown menu working in both mobile and desktop the way that I want, I want to make the list of router-links into its own component. This just so that in the future I can update one component and have it reflected in both mobile and desktop views.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments