# Single-page application routing with Vue Router

> A walkthrough of the core concepts and practical setup I encountered while moving page transitions to the client side with Vue Router.

- Published: 2016-11-06
- Category: Interface
- Tags: Vue.js
- Reading time: 3 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/single-page-application-routing-with-vue-router/
- Language: en-US
- Author: Muhammet Şafak

---
[Back in April I wrote my first component with Vue.js](/en/blog/first-reactive-component-with-vue-js/). Since then I've used it in a handful of small UI pieces, and my positive impression of the reactive approach has only grown. This time I wanted to take a bigger step: setting up a full single-page application (SPA) architecture with Vue Router.

An SPA is an approach where all page transitions happen in the browser. The server delivers a single HTML file and the required assets (JavaScript, CSS) on the first request; every subsequent navigation is handled entirely by JavaScript. No full page reloads, fast transitions.

## What is Vue Router?

**Vue Router** is the official routing library for Vue.js. It maps URLs to components. Install it via `npm`:

```bash
npm install vue-router
```

## Basic setup

First I define the components — each "page" is a Vue component:

```javascript
// components/Anasayfa.js
var Anasayfa = {
    template: '<div><h2>Hoşgeldiniz</h2><p>Ana sayfa içeriği.</p></div>'
};

// components/Hakkimda.js
var Hakkimda = {
    template: '<div><h2>Hakkımda</h2><p>Bu benim sayfam.</p></div>'
};

// components/UrunDetay.js
var UrunDetay = {
    template: '<div><h2>Ürün {{ $route.params.id }}</h2></div>'
};
```

Then I define the routes and create the router:

```javascript
var rotalar = [
    { path: '/',              component: Anasayfa   },
    { path: '/hakkimda',      component: Hakkimda   },
    { path: '/urunler/:id',   component: UrunDetay  }
];

var router = new VueRouter({
    routes: rotalar
});

var uygulama = new Vue({
    router: router,
    el: '#uygulama'
});
```

On the HTML side, the `<router-view>` tag marks where the active component should be rendered:

```html
<div id="uygulama">
    <nav>
        <router-link to="/">Anasayfa</router-link>
        <router-link to="/hakkimda">Hakkımda</router-link>
    </nav>

    <router-view></router-view>
</div>
```

`<router-link>` is used in place of a standard `<a>` tag — it handles the link without triggering a full page reload.

## URL mode: hash vs. history

In the default mode, URLs look like `/#/hakkimda`. This is **hash mode**; it requires no server configuration because the hash fragment is never sent to the server.

For clean URLs (`/hakkimda`), you switch to **history mode**:

```javascript
var router = new VueRouter({
    mode: 'history',
    routes: rotalar
});
```

This mode, however, requires a server-side change: all requests must be redirected to `index.html`. On Nginx that looks like:

```nginx
location / {
    try_files $uri $uri/ /index.html;
}
```

Without this, a direct visit to `/hakkimda` returns a 404 from the server. Apache needs a similar `.htaccess` rule. I skipped this on my first try and spent a good while wondering why things weren't working — it's a common trap when setting up an SPA for the first time.

## Dynamic route parameters

For dynamic routes like a product detail page, I use the `:id` syntax to capture URL parameters:

```javascript
var UrunDetay = {
    template: '<div>Ürün ID: {{ urunId }}</div>',

    computed: {
        urunId: function () {
            return this.$route.params.id;
        }
    },

    created: function () {
        // Fetch data when the page loads
        console.log('Ürün ID:', this.$route.params.id);
    }
};
```

I access the `:id` value from the URL via `this.$route.params.id`. It's available from any method or computed property inside the component.

One thing to watch with dynamic routes: when the same component is reused with different parameters, Vue does not recreate the component — only the parameters change. This means the `created` hook is only called on the initial load. To react to parameter changes you need to watch `$route`; I missed this at first and spent a long time chasing why my data wasn't updating.

## Navigation: programmatic redirects

Sometimes you need to redirect programmatically after an action completes — for example, after a form submission:

```javascript
var UrunEkle = {
    template: '<button @click="kaydet">Kaydet</button>',

    methods: {
        kaydet: function () {
            // Save logic...

            // Redirect to product list
            this.$router.push('/urunler');
        }
    }
};
```

## Observations

Setting up an SPA with Vue Router turned out to be easier than I expected. The relationship between components and routes is clean and easy to reason about.

A few things still puzzle me: routes with multiple parameters, nested routes, transition animations. I need to explore those separately.

There is also the server-side rendering (SSR) question — important for SEO. For now I'm experimenting with the SPA approach on a small admin panel where SEO doesn't matter. For any public-facing application, though, that topic needs to be addressed.

Vue Router is a natural next step within the Vue ecosystem. Pair reactive components with routing and you get a genuine application skeleton.
