Where to Discuss?

Local Group

Preface

Goal: Preparing Vue Application, using Vue router.

Welcome to modern web framework. Oh.. I mean NPM bundle.

We are going to step into Vue component. Just like usual I use step by step explanation. This means four or five Vue components, from mockup, then simple, then enhanced. It is going to be tidy if we can put them all in one application. Each components managed by different links.

To manage all these links, we require router. This is where this article comes in place, before we step into the real components in the next article.

You can also consider this article as introducing to vue application.

Reading Reference:

Official Site


The Terminal Command

Install

As you might have seen in the example, you should install with NPM first.

❯ npm install -g @vue/cli

Vue2 App: NPM: Vue CLI Install

Create App

We should start with creating application

$ vue create vue-hello

And you will have a chance, to get a preconfigured setup, as figure above.

Vue CLI v4.5.9
? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 2] babel, eslint) 
  Default (Vue 3 Preview) ([Vue 3] babel, eslint) 
  Manually select features 

Vue2 App: CLI: Vue Create App

Just continue until its done

🚀  Invoking generators...
📦  Installing additional dependencies...

...

⚓  Running completion hooks...

📄  Generating README.md...

🎉  Successfully created project vue-hello.
👉  Get started with the following commands:

Vue2 App: CLI: Vue Create App

Running for The First Time

You can safely enter the directory

$ cd vue-hello

And run the npm script.

$ npm run serve

After a few moment, there will a message in your terminal.

 DONE  Compiled successfully in 3433ms      3:35:08 PM


  App running at:
  - Local:   http://localhost:8080/ 
  - Network: http://192.168.1.152:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

Vue2 App: CLI: npm run serve

Preview

Consider open your browser, to see result.

Vue2 App: CLI: Default Page

The typical default vue page can be shown as above figure. The title in browser, follow the setting in package.json.

CLI Service

I once have difficulties with cli-service. My workaround is, by also installing this locally, if required.

❯ npm i -s @vue/cli-service-global
+ @vue/cli-service-global@4.5.9
updated 1 package and audited 1380 packages in 29.084s

Vue2 App: NPM: Vue Service Install


The Default Vue2 Hello

App.vue

You should find these structure in src/App.vue

<template>
  <div id="app">
  </div>
</template>

<script>
...
</script>

<style>
...
</style>

You can learn about this structure somewhere else. There are tons of basic tutorial in the internet.

main.js

You may spot the src/main.js file as below.

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

What is this cryptic render: h => h(App) anyway 🤔? It is actually short version of code below.

new Vue({
  el: '#app', // side effect with eslint
  render: function (createElement) {
    return createElement(App);
  }
})

You might also find old tutorial as below:

new Vue({
  el: '#app',
  components: { App },
  template: '<App/>'
})

This style has been deprecated, and might confused people learning from ancient codes. You should use render: h => h(App) instead.

HelloWorld.app

And at last, src/components/HelloWorld.vue With basic Vue component structure.

<template>
  <div class="hello">
  </div>
</template>

<script>
...
</script>

<style>
...
</style>

Using Vue2 Router

If you want to have muliple pages in single application. You can utilize router to manage the application.

Reading Reference:

Official Site

Credits

As a beginner, I once confused about this router. But hey, the community is helpful. I got help from this kind guy.

Install

As usual, we need to install the dependency first, before we can us it.

$ npm i -s -D vue-router
+ vue-router@3.4.9
added 1 package from 1 contributor and audited 1305 packages in 29.198s

Vue2 App: NPM: Vue2 Router Install

Directory Structure

Our directory structure should represent something similar as below:

$ tree -I node_modules
.
├── babel.config.js
├── package.json
├── package-lock.json
├── public
│   ├── favicon.ico
│   └── index.html
├── README.md
└── src
    ├── App.vue
    ├── assets
    │   └── logo.png
    ├── components
    │   └── HelloWorld.vue
    ├── main.js
    └── router
        └── index.js

5 directories, 11 files

Vue2 App: Router: General Tree Structure

We should create the router/index.js manually, this will be explained later.

HelloWorld.vue

Consider we start from the component first. I make this very simple.

<template>
  <div>
    <p><strong>{{ msg }}</strong></p>
  </div>
</template>

<script>
export default {
  name: 'HelloEarth',
  props: {
    msg: { type: String, default: 'Hello Earth!' }
  }
}
</script>

index.js

After we are done with component, we can continue to configure our very first router.

  • src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'default',
      component: HelloWorld,
      meta: { title: 'Hello' }
    }
  ]
})

main.js

And then add it into src/main.js file as below.

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

We are not finished yet.

App.vue

At last, alter the landing page in src/App.vue.

<template>
  <div id="app">
    <router-link to="hello">Hello</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
body { font-family: Arial, Helvetica, sans-serif; }
#app { margin: 1rem; }
a    { padding-right: 1rem; }
</style>

Preview

Consider open your browser, to see result.

Vue2 App: Preview: Simple Router Page

The very simple page of vue router example, can be shown as above figure.


Vue2 Multiple Component

We can leverage the basic example above with more component.

Directory Structure

$ tree src
src
├── App.vue
├── assets
├── components
│   ├── AlohaWorld.vue
│   ├── HelloWorld.vue
│   ├── TitleHeading.vue
│   └── YelloWorld.vue
├── main.js
└── router
    └── index.js

3 directories, 7 files

Note that we have a TitleHeading component in above tree.

Vue2 App: Router: Router Tree Structure

Greeting Component

The HelloWorld is remain intact.

We have two more components:

<template>
  <div>
    <p><strong>{{ msg }}</strong></p>
  </div>
</template>

<script>
export default {
  name: 'AlohaMaui',
  props: {
    msg: { type: String, default: 'Aloha Maui!' }
  }
}
</script>
<template>
  <div>
     <p><strong>{{ msg }}</strong></p>
  </div>
</template>

<script>
export default {
  name: 'YelloWorld',
  props: {
    msg: { type: String, default: 'Yellow World!' }
  }
}
</script>

index.js

Now we can seriously make a real router:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import AlohaWorld from '@/components/AlohaWorld'
import YelloWorld from '@/components/YelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'default',
      component: YelloWorld,
      meta: { title: 'Yellow' }
    },
    {
      path: '/hello',
      name: 'Hello',
      component: HelloWorld,
      meta: { title: 'Hello' }
    },
    {
      path: '/aloha',
      name: 'Aloha',
      component: AlohaWorld,
      meta: { title: 'Aloha' }
    },
    {
      path: '/yellow',
      name: 'Yellow',
      component: YelloWorld,
      meta: { title: 'Yellow' }
    }
  ]
})

But what is this additional meta title anyway 🤔?

Heading Component

This TitleHeading is using this $route.meta.title variable.

<template>
  <section>
    <h1>{{ $route.meta.title }}</h1>
  </section>
</template>

<script>
export default {
  name: 'TitleHeading'
}
</script>

This way, we can set different title, based on page setting in route configuration.

App.vue

We should gather all these components above in src/App.vue.

<template>
  <div id="app">
    <TitleHeading/>

    <router-link to="hello">Hello</router-link>
    <router-link to="aloha">Aloha</router-link>
    <router-link to="yellow">Yellow</router-link>

    <router-view></router-view>

    <p>I love myself as well.</p>
  </div>
</template>

<script>
import TitleHeading from './components/TitleHeading.vue'

export default {
  name: 'App',
  components: {
    TitleHeading
  }
}
</script>

<style>
body { font-family: Arial, Helvetica, sans-serif; }
#app { margin: 1rem; }
a    { padding-right: 1rem; color: #00796b; }
</style>

Consider also have a nice link color in stylesheet.

Finishing with main.js

We want the title to be also dynamically changed right? Then append these additional code into src/main.js file as below.

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
  computed: {
    pageTitle: function() {
      return this.$route.meta.title;
    }
  },
  created () {
    document.title = this.$route.meta.title;
  },
  watch: {
    $route(to) {
      document.title = to.meta.title;
    },
  }
}).$mount('#app')

Preview

Consider open your browser, to see result.

Vue2 App: Preview: Router with Different Page

The multi component of vue router example in a single page, can be shown as above figure.

Just click each link, and the content would be changed instantly.

Vue2 App: Preview: Router with Different Page


Using Vue3 Router

Vue3 had released in late 2020. You can also utilize Vue3. It is very similar with Vue2.

Reading Reference:

Official Site

Install

As usual, we need to install the dependency first, before we can us it.

$ npm i -s -D vue-router@next
+ vue-router@4.0.0-rc.6
updated 1 package and audited 1327 packages in 30.097s

Vue3 App: NPM: Vue Router Install

Reusable Component

We don’t need three component to do the same task. We can utilize this single HelloWorld.vue component only, and throw away the other two components.

you wasted me up, and dumped me from the mountain you wasted me up, and throw me from to the sea

Directory Structure

$ tree src
src
├── App.vue
├── assets
├── components
│   ├── HelloWorld.vue
│   └── TitleHeading.vue
├── main.js
└── router
    └── index.js

3 directories, 5 files

Vue3 App: Router: Router Tree Structure

App.vue

We should gather all these components above in src/App.vue.

It is exactly the same as the previous Vue2 version.

main.js

The main.js has a new syntax, as shown below:

import { createApp, reactive } from 'vue'
import App from './App.vue'
import router from './router'

const Title = reactive({
  computed: {
    pageTitle: function() {
      return this.$route.meta.title;
    }
  },
  created () {
    document.title = this.$route.meta.title;
  },
  watch: {
    $route(to) {
      document.title = to.meta.title;
    },
  }
})

createApp(App)
  .use(router)
  .mixin(Title)
  .mount('#app')

In Vue3 we have chain functions: use, mixin, and mount.

Heading Component

The TitleHeading is remain intact. It is exactly the same as previous Vue2 code.

HelloWorld.vue

Is there any changes here?

<template>
  <p><strong>{{ msg }}</strong></p>
</template>

<script>
export default {
  name: 'HelloEarth',
  props: {
    msg: { type: String, default: 'Hello Earth!' }
  }
}
</script>

Yes, the previous Vue2 version has more div:

<template>
  <div>
    <p><strong>{{ msg }}</strong></p>
  </div>
</template>

index.js

Finnaly the router itself. We can adapt the previous code to Vue3 writing style.

import { createWebHistory, createRouter } from "vue-router";
import HelloWorld from '@/components/HelloWorld'

const routes = [
  {
    path: '/',
    name: 'default',
    component: HelloWorld,
    meta: { title: 'Yellow' },
    props: { msg: 'How Are You?' }
  },
  {
    path: '/hello',
    name: 'Hello',
    component: HelloWorld,
    meta: { title: 'Hello' },
    props: { msg: 'Hello Earth!' }
  },
  {
    path: '/aloha',
    name: 'Aloha',
    component: HelloWorld,
    meta: { title: 'Aloha' },
    props: { msg: 'Aloha Maui!' }
  },
  {
    path: '/yellow',
    name: 'Yellow',
    component: HelloWorld,
    meta: { title: 'Yellow' },
    props: { msg: 'Yellow World!' }
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

As you can see in above routes, they all use the same HelloWorld component.

Simpler right?

Preview

It is exactly the same as previous.

Vue3 App: Preview: Router with Different Page


Vue Mixin

This is a Vue2 feature that I can use in Vue3.

In the next article I require three components, all with the same template structure, but different behaviour. How am I going to achieve this in Vue?

mixin comes to rescue We can go further from previous example.

TemplateAbstract.vue

First we have to move the template to other components.

<template>
  <p><strong>{{ msg }}</strong></p>
</template>

This component contain the structure, only <template>. The real world template structure, might be longer, with a few line of tags.

HelloWorld.vue

Then use it somewhere, with mixin.

<script>
import TemplateAbstract from '@/components/TemplateAbstract'

export default {
  mixins:[TemplateAbstract],
  name: 'HelloEarth',
  props: {
    msg: { type: String, default: 'Hello Earth!' }
  }
}
</script>

This component contain behaviour only, in <script>. The real world script behaviour, may vary between different components.

Preview

It is exactly the same as previous. There is no need for more figure here.

And we are done.


What’s Next?

It is a good time to go back to our very tabs component. But this time we will represent in Vue CLI fashioned.

Consider continue reading [ Tabs - JS - Vue2 Application ].