DEV Community

Cover image for An Easy, Comprehensive and Practical Guide to Vue3
prodbyola
prodbyola

Posted on • Edited on

An Easy, Comprehensive and Practical Guide to Vue3

Vue.js is a popular open-source JavaScript framework used for building user interfaces and single-page applications. If you already understood the basics of HTML, CSS and Javascript/Typescript, then using VueJS is going to be all familiar to you. In this tutorial, we'll learn how to build interactive web apps using Vue. You can find the project's source code here.

Technical Prerequisite

It is required that you have the following tools installed in order to follow this tutorial.

  • Latest VSCode (or an IDE of your choice).
  • Latest NodeJS.
  • Latest Yarn (or any other Javascript package manager).

Knowledge Prerequisite

A basic understanding of HTML, CSS and Javascript/Typescript is required for this tutorial.

Create Vue Project

The first thing we're going to do is create a new Vue project:

  • Now open your VSCode, press Ctrl + J to open the terminal and type yarn create vue@latest into the terminal. Press Enter key.
  • Answer the prompts as below. Use arrow keys to navigate left/right when selecting your answers:

Creating New Vue Project

  • When you're done, type cd todo && yarn install to install the project dependencies.
  • Now type yarn add sass to add support for SCSS.
  • Type code . to load the project in VSCode. Notice the . after "code".
  • Once VSCode opens your new project, press Ctrl + J and type yarn dev. Your project will be launched on http://localhost:5173/.
  • If all went well, then you should see a page like below in your page.

New Vue Project Page

  • Press Ctrl + C from the terminal to close your project server.

Project Structure

Before we go further, let me quckly introduce you to the src folder in your project.

  • App.vue is the base vue Single File Component(SFC) that holds your project together. Every component (or vue file) is an SFC. We'll talk about SFCs later but keep in mind that a Vue Component is a reusable and self-contained unit of Vue file that encapsulates a piece of UI functionality. For example, to create a custom reusable Button, you may create a simple Vue Component like AppButton.vue which will contain all the layout, styling and functionalities of the button.
  • The src/components folder is where you'll keep all your small units of UI (components).
  • The src/views folder is where you'll keep your app pages.
  • The src/router is where we configure the app navigation i.e, which route leads to which page.
  • src/stores is where we write app's global states. You'll learn more about this later.
  • src/assets is where we keep static assets like fonts, css and sometimes, images.

Vue App Layout
Technically, every box in the image is a vue component or SFC but we generally refer to Component.vue boxes as "components". In this structure, App.vue is the main app, HomeView.vue and AboutView.vue are different pages within the app and every Component.vue is a vue-styled UI component within each page. This is similar to how HTML DOM tree is structured: parents, children, siblings...etc.

Prepare to Build

Now let's take some steps to prepare our project for building:

  • Go to src/components folder and delete all the files and folders inside as we won't be needing them.
  • Now go to src/views folder and delete AboutView.vue file. We won't be needing that as well.
  • Our app router (navigator) will try to locate AboutView.vue and we get an error because we've deleted the file. To fix this, go to router/index.ts and delete the lines as in the red box:

Prepare Vue project for buiding

  • Now go to src/views/HomeView.vue and replace the existing code with this:
<template>
  <div></div>
</template>
Enter fullscreen mode Exit fullscreen mode
  • Go to src/App.vue and replace the existing code with this code:
<template>
  <main>
    <RouterView />
  </main>
</template>
Enter fullscreen mode Exit fullscreen mode
  • We'll be using Google font Poppins in our app. We can import this font from Google's CDN. Go to src/assets/main.css and paste this at the top of the file @import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap');. Then add this CSS code to the file (below all import statements):
body {
  font-family: 'Poppins', sans-serif;
  color: rgb(100, 99, 99);
}
Enter fullscreen mode Exit fullscreen mode

Now your project should be empty and you're ready to start building.

Create Your First SFC

It's time to create your First UI component, an SFC. Vue's Single File Component allows you to define the HTML, CSS and Javascript sections of your UI in just one file. You define the HTML in template tag, CSS in style tag and Javascript in script tag. Let's see how that works:

  • Create a file src/components/TodoCard.vue;
  • Put this HTML section in the file:
<template>
  <div class="todo_card">
    <h3 class="task_title">Buy groceries</h3>
    <p class="task_details">
      I'll be visiting FoodCo this afternoon to stock more Milk, eggs, bread and fruits for this
      week. Don't forget to get Elubo and Garri😂
    </p>
    <div class="tdc_footer">
      <div class="task_cat"></div>
      <div class="task_done">
        <input type="checkbox" />
        <p>Done</p>
      </div>
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode
  • Now add this CSS section after the template tag:
<style lang="scss" scoped>
  .todo_card {
    width: 370px;
    font-size: 0.92rem;
    background-color: rgba(255, 255, 0, 0.289);
    padding: 18px 28px;
    border-radius: 12px;
    box-shadow: rgba(0, 0, 0, 0.15) 1.95px 1.95px 2.6px;

    .task_title {
      font-size: 1.2rem;
      font-weight: 500;
    }

    .task_details {
      margin: 8px auto 24px auto;
      height: 70px;
    }

    .tdc_footer {
      display: flex;
      align-items: center;
      justify-content: space-between;

      .task_cat {
        width: 24px;
        height: 24px;
        border-radius: 50%;
        background-color: rgba(137, 43, 226, 0.308);
      }

      .task_done {
        display: inline-flex;
        align-items: center;
        column-gap: 8px;
        cursor: pointer;
      }
    }
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Notice the scoped attribute on the style tag? This tells Vue to apply the style to elements ONLY in this particular component. If you want the style to be applied globally, remove the scoped attribute. Save your file.

Now let's import our component and display it on HomeView.

  • Go to src/views/HomeView.vue and add the typescript section to import TodoCard.vue:
<script setup lang="ts">
  import TodoCard from '@/components/TodoCard.vue'
</script>
Enter fullscreen mode Exit fullscreen mode

Did you notice the setup attribute on the script tag? This makes the script tag to use Vue's Composition API which we'll use to interact with Vue's reactive APIs. More of this later.

Now use TodoCard component in the template of HomeView:

<template>
  <div>
    <TodoCard />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Save HomeView file and run yarn dev in the terminal to relaunch your app.

Creating vue app

Now we can say HomeView is the parent component of TodoCard because the former now hosts the latter.

Interpolation and Data Binding

It's time to share data between the HTML and Javascript sections of your component. The is known as data interpolation or data binding. It means you can declare a variable in script tag and attach its value to an HTML element in template tag for display. For example, let's create our task data as Javascript variables and render them in HTML. Go to src/components/TodoCard.vue and script tag below the style tag:

<script setup lang="ts">
  const taskTitle = 'Buy groceries'
  const taskDetails =
    "I'll be visiting FoodCo this afternoon to stock more Milk, eggs, bread and fruits for this week. Don't forget to get Elubo and Garri😂"
</script>
Enter fullscreen mode Exit fullscreen mode

Now replace the original contents in HTML with those Javascript variables this way:

<template>
  <div class="todo_card">
    <h3 class="task_title">{{ taskTitle }}</h3>
    <p class="task_details">{{ taskDetails }}</p>
    <div class="tdc_footer">
      <div class="task_cat"></div>
      <div class="task_done">
        <input type="checkbox" />
        <p>Done</p>
      </div>
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Save your file and you'll see your app is working. Notice how we surround the Javascript variable name with double curly brackers {{ }} to distinguish from literal HTML content. Of course we can combine this with raw HTML contents:

<h3 class="task_title">Task title is {{ taskTitle }} for this task</h3>
Enter fullscreen mode Exit fullscreen mode

We can also bind Javascript variable to HTML attributes. Ok, let's say our h3 tag has an id attribute:

<h3 id="task-title" class="task_title">{{ taskTitle }}</h3>
Enter fullscreen mode Exit fullscreen mode

We can pass attribute value from Javascript to this tag using vue's v-bind directive shorthand:

<template>
  ...
  <h3 :id="taskId" class="task_title">{{ taskTitle }}</h3>
  ...
</template>

<script setup lang="ts">
  const taskId = "task-001"
  ...
</script>
Enter fullscreen mode Exit fullscreen mode

With this, the id attribute of the h3 tag will now be "task-001". Notice the : before the attribute. That's how we tell HTML that we're about to pass Javascript as the attribute's value. This can help us to manipulate HTML contents dynamically as we'll see soon.

Props

Let's say we want to define a task object in the parent component HomeView and display the object using TodoCard. So instead of rendering our task data directly from TodoCard, we define an object that represents this data in HomeView and pass it to TodoCard. We can achieve this with props. Props is how we pass data from parent components to child components:

  • Define task object in HomeView. We still have the same data as before, except we now have it in an object with an extra done member to indicate whether the task is done. We'll use this later:
<template>
  <div>
    <TodoCard />
  </div>
</template>

<script setup lang="ts">
  import TodoCard from '@/components/TodoCard.vue'

  const task = {
    title: 'Buy groceries',
    details:
      "I'll be visiting FoodCo this afternoon to stock more Milk, eggs, bread and fruits for this week. Don't forget to get Elubo and Garri😂",
    done: false
  }
</script>
Enter fullscreen mode Exit fullscreen mode
  • Now we need to pass this data down to TodoCard but first, we should define the props signature that TodoCard must accept. Update the script section of TodoCard.vue:
<script setup lang="ts">
  defineProps<{
    title: string
    details: string
    done: boolean
  }>()
</script>
Enter fullscreen mode Exit fullscreen mode
  • Now any parent component that uses TodoCard must supply values to these props as attributes. Let's update TodoCard template to display the props data:
<template>
  <div class="todo_card">
    <h3 class="task_title">{{ title }}</h3>
    <p class="task_details">{{ details }}</p>
    <div class="tdc_footer">
      <div class="task_cat"></div>
      <div class="task_done">
        <input type="checkbox" :checked="done" />
        <p>Done</p>
      </div>
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode
  • Update our usage of TodoCard in HomeView to receive the props:
<template>
  <div>
    <TodoCard :title="task.title" :details="task.details" :done="task.done" />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Iteration

Our task at the moment is just one hardcoded task object. But we'll have multiple tasks in our app. We can simulate this by creating an array of tasks and display them all using the same TodoCard component and v-for directive.

  • In HomeView, let's create a tasks array that contains 3 task objects:
<script setup lang="ts">
  import TodoCard from '@/components/TodoCard.vue'

  const tasks = [
    {
      title: 'Buy groceries',
      details:
        "I'll be visiting FoodCo this afternoon to stock more Milk, eggs, bread and fruits for this week. Don't forget to get Elubo and Garri😂",
      done: false
    },
    {
      title: 'Finish homework',
      details: 'Math assignment and essay due tomorrow. I have to complete them tonight.',
      done: true
    },
    {
      title: 'Call mom',
      details: "Wish her a happy birthday and remind her to get dad's pair of glasses.",
      done: false
    }
  ]
</script>
Enter fullscreen mode Exit fullscreen mode
  • Now let's use vue's v-for directive to iterate over each task object in tasks and pass them to TodoCard for display:
<template>
  <div>
    <TodoCard
      v-for="(task, index) in tasks"
      :key="index"
      :title="task.title"
      :details="task.details"
      :done="task.done"
    />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Notice how we add an extra key attribute that accepts index, which is the unique index of an item in the array. The key attribute is required by vue to uniquely identified each item in the DOM when you create a loop using the v-for directive.

Vue v-for directive

We need to lay our items out horizontally. Let's place them in a CSS flex container.

  • Create style section in HomeView:
<style lang="scss" scoped>
  .task_list {
    display: flex;
    flex-wrap: wrap;
    column-gap: 16px;
    row-gap: 16px;
    width: 100%;
  }
</style>
Enter fullscreen mode Exit fullscreen mode
  • Now update the template so the contents are placed within task_list:
<template>
  <div class="task_list">
    <TodoCard
      v-for="(task, index) in tasks"
      :key="index"
      :title="task.title"
      :details="task.details"
      :done="task.done"
    />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode
  • Lastly, update src/assets/main.css so that this is all you have:
@import './base.css';
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap');

#app {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  font-weight: normal;
}

body {
  font-family: 'Poppins', sans-serif;
  color: rgb(100, 99, 99);
}
Enter fullscreen mode Exit fullscreen mode

Creating Vue app

We're not done exploring! Proceed to Part 2.

If you would like to connect, please contact me.

Top comments (0)