What a beautiful day to learn a new framework! In this post, let us delve into the world of Vue, specifically Vue 3. I will oversimplify the explanation of technologies used in this tutorial to focus on the good stuff: creating a functional website. However, if you want further reading regarding any topics, links to their documentation will be provided.
Introduction
There are a couple of ways to use Vue 3 in your project, just as mentioned in their guide. I have chosen to use Node to set up our workspace for this post.
Node
Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.
If you are familiar with Javascript, you would have probably heard of Node. It is the building block of many websites in the world today. Created by Ryan Dahl, this technology allows you to extend the functionalities of your website exponentially.
Specifically, I will install Node because of the Node Package Manager or npm. It is to install vast amounts of frameworks such as React, Svelt, Angular and, of course, Vue.
To install Node, you can just follow the instructions on their website. In a nutshell, you would need to download the installer, run it, agree to all conditions and restart your computer when prompted.
Install PNPM
I am a user of pnpm because I feel that it is a more efficient and fast package manager. To install globally on your computer, open your command prompt and run the following:
npm install -g pnpm
You can check out their documentation here.
Vue 3
Javascript frameworks exist to simplify web development. Vue 3 is lightweight and has an easy-to-understand syntax. The ability to split your website into functional components makes the overall development experience much more enjoyable. You can also save time significantly by focusing more on your website logic rather than the complexities of manipulating DOM elements. Here is a simple difference when adding two numbers
- Vanilla JS
<p id="demo"></p>
<script>
document.getElementById('demo').innerHTML = 2 + 2;
</script>
- Vue
<p>{{ 2 + 2 }}</p>
Vite
Vue is a language that is unrecognizable for the browser. Therefore, the ‘bundling’ of code is required to view the result. For this project, I will use Vite (a French word for “quick”, pronounced /vit/, like “veet”) for one simple reason; it’s fast.
If you are familiar with webpack or Rollup, try Vite. You will feel the difference. More about how Vite is created to solve problems here.
What we are building
Today, I will build a sortable product list using different criteria to showcase creating a website with Vue. Here is a preview of the website:
And here is the link to the repository:Create a Vite project
First, create a folder or use an existing folder for this project. For example, I will be using the C:\Websites\
folder. Open the command prompt and direct to this folder. If you are on Windows, you can type cmd
in the address bar in the C:\Websites\
folder.
The command prompt will display something like this based on what you name your folder.
C:\Websites>
This command will create a new folder for this post:
pnpm create vite product-sorter-vue3 -- --template vue
product-sorter-vue3
is replaceable with any name that you prefer.
After the project is scaffolded, run the following command to go inside the folder you just created:
cd product-sorter-vue3
Then run this to install all dependencies:
pnpm i
Once its done, run this command to run a development server:
pnpm dev
Then you can go to http://localhost:3000/
to view this:
As you can see in the preview, it is recommended to use VSCode and Volar, an extension in VSCode, for syntax highlighting and a better Vue 3 development experience.
To stop the dev server, click ctrl + c
, then type Y
to confirm. At the same folder and if you are on Windows, you can type
code .
to open this project in VSCode (already installed). For Mac users, you can check out this documentation.
Single Page Application (SPA)
Vue is a framework that is originally created as a Single Page Application or SPA. This means that it only serves a single index.html
document. All of the functions and page route is manipulated by javascript. We can see this structure when we go to index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
As declared in index.html
, main.js
is the javascript file that takes over the whole document. Vue is initialized in this file and looks like this:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
Vue Structure
All vue structure has 3 major tags in a Single File Component (SFC):
<script>
This is the place where you write most of your logic in javascript or typescript.<template>
Normal html tags apply here.<style>
This is where you keep the CSS for the SFC. If you wish to make the style apply to the current elements only, add<style scoped>
Check out App.vue
for a sample:
<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Hello Vue 3 + Vite" />
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
For this post, I will focus on the <script setup>
Composition API rather than the traditionally used Options API. Some advantages are as follows:
- Concise code with less boilerplate
- Ability to declare props and emitted events using pure TypeScript
- Better runtime performance
- Better IDE type-inference performance
Check out the documentation here for a full description. All in all, I believe that the composition API is much easier to write code, has typescript support and is more manageable in the event of your code getting bigger.
If you wish to use typescript, add
<script setup lang="ts">
Components
Hello World
Notice the HelloWorld
component being imported and used in the template. As your website grows, more components will be imported and manipulated in various ways.
When information is passed inside a component, it is called a prop. When data is coming from the component to be received by the parent, its called an emit.
In App.vue
, the string Hello Vue 3 + Vite
is passed as a prop. The name of the prop is msg
. And if we go to HelloWorld.vue
inside the components directory, we can see how this prop is received:
defineProps({ msg: String })
Now, you can call the prop inside the template like so:
<h1>{{ msg }}</h1>
Pretty simple right?
Count
In Vue, event-handling is using a v-on
directive. It is usually shortened to just the @
symbol. Let us now look at the button that increases by 1 at every click. To implement this, ref
is imported to make the count
variable reactive. This is done in the <script setup>
:
import { ref } from 'vue'
const count = ref(0)
Then, in the template, a click event is added to a button to signify that the count value to increase by 1 at every click.
<button type="button" @click="count++">count is: {{ count }}</button>
Read more about Javascript Operators Reference here.
Now, I will delete the HelloWorld.vue
component and the contents of App.vue
to start creating our project.
App.Vue
Script Setup
First, I will import ref and also a ProductList component (to be created later):
import { ref } from 'vue'
import ProductList from './components/ProductList.vue'
Then I will generate random products to use in this demonstration:
const products = ref([
{ title: 'Phone', colour: 'Grey', price: 549, id: 1 },
{ title: 'Mechanical Keyboard', colour: 'Blue', price: 79, id: 2 },
{ title: 'LCD Monitor', colour: 'Black', price: 127, id: 3 },
{ title: 'Desktop', colour: 'Red', price: 2132, id: 4 },
{ title: 'Laptop', colour: 'White', price: 1264, id: 5 },
])
I will also create a variable for the sorting order. The default value is title
:
const orderBy = ref('title')
Then, the function to fire when we click on a different term:
const handleClick = (term) => {
orderBy.value = term
}
Template
The main title:
<h1 class="title">The Store</h1>
The buttons to sort the products
<div class="orders">
<button @click="handleClick('title')">Title</button>
<button @click="handleClick('colour')">Colour</button>
<button @click="handleClick('price')">Price</button>
</div>
The component that shows a list of products that we will create
<ProductList :products="products" :orderBy="orderBy" />
Style
Finally, just some styling to make this demonstration looks a little more presentable:
@import url('https://fonts.googleapis.com/css2?family=Corinthia:wght@700&display=swap');
html {
background-color: whitesmoke;
}
#app {
font-family: Verdana, Geneva, Tahoma, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
margin: 60px auto;
}
.orders {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
max-width: 90%;
margin: 0 auto;
}
@media (min-width: 600px) {
.orders {
max-width: 600px;
}
}
.orders button {
margin: 2px;
padding: 20px;
cursor: pointer;
font-weight: bold;
border-radius: 10px;
color: #2c3e50;
background-color: rgb(255, 247, 203);
box-shadow: lightslategray 0 1px 2px;
border: none;
transition: all ease 0.3s;
}
.orders button:hover {
background-color: rgb(241, 237, 212);
}
.title {
color: gold;
text-shadow: 2px 2px #2c3e50;
font-family: 'Corinthia', cursive;
font-size: 100px;
margin: 0;
}
ProductList.vue
Scripts
Inside the components folder, I will create a ProductList.vue to handle the props received from App.vue. First, I will import the computed function to create a function to sort the products:
import { computed } from 'vue'
Then, define the props received from App.vue
const props = defineProps({ products: Array, orderBy: String })
Lastly, I create a function to sort the products in different order terms like so:
const orderedProducts = computed(() => {
return [...props.products].sort((a, b) => {
return a[props.orderBy] > b[props.orderBy] ? 1 : -1
})
})
Template
The template is fairly straightforward. A line to inform of the current sorting term:
<p>Sort by: {{ orderBy }}</p>
v-for
In Vue, we can loop through an array using the v-for loop and extract each element like this:
<div class="product" v-for="product in orderedProducts" :key="product.id">
<h1>{{ product.title }}</h1>
<p>{{ product.colour }}</p>
<p>${{ product.price }}</p>
</div>
Transition
Then I will wrap the loop with a <transition-group>
for the animation. If you were to animate a single div, you can use <transition>
to achieve that. I will name my animation sorter
. You can name your animation to whichever you prefer.
<div class="product-container">
<transition-group name="sorter">
<div class="product" v-for="product in orderedProducts" :key="product.id">
<h1>{{ product.title }}</h1>
<p>{{ product.colour }}</p>
<p>${{ product.price }}</p>
</div>
</transition-group>
</div>
Style
After that, I will declare the styles for this SFC like so:
.product-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.product {
height: 100%;
width: 40%;
padding: 10px 0;
margin: 5px;
box-shadow: lightslategray 0 1px 2px;
border-radius: 10px;
background-color: #fdfdfd;
}
.product h1 {
font-size: large;
}
.sorter-move {
transition: all 1s;
}
Notice that the .sorter-move
class is defined just to show the movement when the products are sorted. Other than -move
, you can also add other classes in Vue for animation such as:
- v-enter-from
- v-enter-active
- v-enter-to
- v-leave-from
- v-leave-active
- v-leave-to
You can read more about animating in Vue 3 in the following link.
Wrapping it up
Here are the live preview of the website and the repo for your reference:
Try clicking on the different terms and watch how the product sorts and the title changes.
Vue makes it easy to design a functional web app without worrying too much of the technical aspects as compared to using vanilla javascript. This is especially crucial if you are a developer that focuses on delivering a finished product as soon as possible.
How have you find this tutorial? What kind of tutorial would you like to see me write about? Do comment here and let me know about it.