Skip to content
DevNursery.com - New Web Developer Docs
GitHub

VueJS

Vue.js: Getting Started

What is Vue.js?

Vue.js is a progressive JavaScript framework for building user interfaces. It is designed to be incrementally adoptable, which means you can integrate Vue.js into your existing projects or use it to build new ones from scratch. Vue.js focuses on the view layer of your application, providing a flexible and efficient way to manage and render UI components.

Vue.js offers several key features and benefits:

  • Declarative Rendering: With Vue.js, you can describe your UI’s structure and behavior declaratively using simple and intuitive template syntax.

  • Component-Based Architecture: Vue.js encourages the creation of reusable and composable components, making it easier to manage complex UIs.

  • Reactivity: Vue.js automatically updates the DOM when your data changes, eliminating the need for manual DOM manipulation.

  • Directives: Vue.js includes a set of built-in directives that help you perform common tasks like conditional rendering, looping, and event handling.

  • Efficient Update Handling: Vue.js uses a virtual DOM and a smart diffing algorithm to update the DOM efficiently, minimizing unnecessary re-renders.

Getting Started with Vue.js

To start using Vue.js, you have a few options:

  • Complete Build Setup: For a more comprehensive development environment, you can scaffold a Vue Single Page Application (SPA) on your local machine. This setup uses Vite as the build tool and supports Vue Single-File Components (SFCs).

Before you begin, make sure you have Node.js version 16.0 or higher installed. Then, follow these steps:

Open your command line and navigate to the directory where you want to create your project.

Run the following command:

npm create vue@latest

This command installs and runs create-vue, the official Vue project scaffolding tool. You’ll be prompted to configure various project options, such as TypeScript support, Vue Router, and more. You can choose the options that best suit your needs.

Once the project is created, navigate to the project directory:

cd <your-project-name>

Install project dependencies:

npm install

Start the development server:

npm run dev

Your Vue project is now up and running!

Using Vue from CDN: If you prefer to keep things simple and use Vue.js directly from a CDN, you can include the global build of Vue in your HTML file:

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

You can then create and mount your Vue app as shown in the example provided in the documentation.

These are the basic steps to get started with Vue.js. Depending on your project’s requirements and your familiarity with build tools, you can choose the approach that best suits your needs. As you continue to work with Vue.js, you can explore more advanced features and tooling options to enhance your development workflow.

Writing Components in Vue

Components in Vue.js allow us to create independent and reusable pieces of user interface, enabling us to think about each part of our application in isolation. In many Vue applications, you’ll find that the UI is organized as a tree of nested components, similar to how we nest native HTML elements. However, Vue brings its own component model to the table, allowing us to encapsulate custom content and logic in each component. Vue also works seamlessly with native Web Components, providing flexibility in your application architecture.

Defining a Component

Single-File Components (SFC)

In Vue, when using a build step, components are typically defined in dedicated files with a .vue extension, known as Single-File Components (SFCs). An SFC contains three main sections:

<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

<template>
  <button @click="count++">You clicked me {{ count }} times.</button>
</template>

The

Plain JavaScript Object (No Build Step)

When not using a build step, you can define a Vue component as a plain JavaScript object containing Vue-specific options. Here’s an example:

import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    return { count }
  },
  template: `
    <button @click="count++">
      You clicked me {{ count }} times.
    </button>`
}

In this case, the template is defined as a JavaScript string, and Vue compiles it on-the-fly. Alternatively, you can target an in-DOM template element by using an ID selector.

Using a Component

To use a child component within a parent component, you need to import it. Assuming the child component is stored in a file called ButtonCounter.vue, you can import it in the parent component like this:

<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script>

<template>
  <h1>Here is a child component!</h1>
  <ButtonCounter />
</template>

With

Components can be reused multiple times within the same parent component or in different parts of your app.

<template>
  <h1>Here are many child components!</h1>
  <ButtonCounter />
  <ButtonCounter />
  <ButtonCounter />
</template>

Each instance of a component maintains its own separate state, which is why you see independent counts in this example.

Passing Props

Props are a way to pass data from a parent component to a child component. Imagine you’re building a blog and you want to create a component to display blog posts. You want each blog post to have its own title. You can define a prop in your child component like this:

<!-- BlogPost.vue -->
<script setup>
defineProps(['title'])
</script>

<template>
  <h4>{{ title }}</h4>
</template>

defineProps is a compile-time macro available inside

In your parent component, you can then pass the title data to the child component like this:

<template>
  <BlogPost title="My journey with Vue" />
  <BlogPost title="Blogging with Vue" />
  <BlogPost title="Why Vue is so fun" />
</template>

Props allow you to pass dynamic data to child components and make your components more reusable.

Listening to Events

Components can communicate with their parent components through custom events. Let’s say you have a button in a child component that, when clicked, should trigger an action in the parent component, like enlarging the text of all posts. Here’s how you can achieve that:

In the child component’s template, emit a custom event when the button is clicked:

<!-- BlogPost.vue -->
<template>
  <div class="blog-post">
    <h4>{{ title }}</h4>
    <button @click="$emit('enlarge-text')">Enlarge text</button>
  </div>
</template>

In the parent component, listen for this event and define the action to be taken:

<template>
  <BlogPost
    v-for="post in posts"
    :key="post.id"
    :title="post.title"
    @enlarge-text="postFontSize += 0.1"
  />
</template>

This example demonstrates how child components can emit events to notify their parent components of user interactions.

Content Distribution with Slots

Slots in Vue allow you to pass content into a component from its parent component. You can use slots to create flexible and customizable components. Here’s a basic example of how slots work:

In the parent component’s template, you can pass content to a child component within its tags:

<AlertBox>
  Something bad happened.
</AlertBox>

In the child component, you define where the passed content should be displayed using the element:

<template>
  <div class="alert-box">
    <strong>This is an Error for Demo Purposes</strong>
    <slot />
  </div>
</template>

Slots allow you to create components that can receive and render dynamic content, making your components more versatile.

Dynamic Components

Sometimes, you need to switch between different components dynamically. Vue provides a element for this purpose. You can change the displayed component by binding the is attribute to the name or object of the component you want to render:

<template>
  <component :is="currentComponent"></component>
</template>

This dynamic component rendering is useful in scenarios like tabbed interfaces where you want to switch between different content.

That covers the basics of writing components in Vue. Components are a fundamental building block of Vue.js applications, and understanding how to create and use them effectively is crucial for building scalable and maintainable Vue applications.

Handling Reactive State in Vue

Reactivity is at the heart of Vue’s ability to create dynamic and responsive user interfaces. In Vue, you can handle reactive state using the Composition API, which provides powerful tools for managing your application’s data.

Declaring Reactive State with ref()

In the Composition API, the recommended way to declare reactive state is by using the ref() function. This function takes an initial value as its argument and returns a reactive reference to that value.

import { ref } from 'vue'

const count = ref(0)

When you declare a ref, it wraps the value in an object with a .value property. To access the value itself, you use .value.

console.log(count)         // { value: 0 }
console.log(count.value)   // 0

count.value++
console.log(count.value)   // 1

In your component’s template, you can directly use count without appending .value. Vue automatically unwraps refs when used in templates.

export default {
  setup() {
    const count = ref(0)

    // Expose the ref to the template
    return {
      count
    }
  }
}
<template>
  <div>{{ count }}</div>
</template>

For more complex logic, you can also declare functions that mutate refs and expose them as methods alongside the state.

import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)

    function increment() {
      count.value++
    }

    return {
      count,
      increment
    }
  }
}

These exposed methods can then be used as event handlers in your template.

<template>
  <button @click="increment">
    {{ count }}
  </button>
</template>

Using

When using Single-File Components (SFCs), you can simplify the setup and usage of reactive state by using the <script setup> syntax:

<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">
    {{ count }}
  </button>
</template>

With <script setup>, top-level imports, variables, and functions are automatically available in the template, making your code more concise.

Why Use Refs?

You might be wondering why we use refs with the .value property instead of plain variables. This is because Vue’s reactivity system relies on tracking property access and mutations. When you use a ref in a template and later change its value, Vue detects the change and updates the DOM accordingly.

Refs provide a way to intercept property access and mutations, which is not possible with plain variables. The .value property allows Vue to track changes and trigger updates when needed.

Additionally, refs can be passed into functions while retaining access to the latest value and the reactivity connection, making them useful for refactoring complex logic into reusable code.

Deep Reactivity

Refs can hold various value types, including deeply nested objects, arrays, and JavaScript built-in data structures like Map. A ref automatically makes its value deeply reactive, ensuring that changes are detected when you mutate nested objects or arrays.

import { ref } from 'vue'

const obj = ref({
  nested: { count: 0 },
  arr: ['foo', 'bar']
})

function mutateDeeply() {
  obj.value.nested.count++
  obj.value.arr.push('baz')
}

However, you can opt-out of deep reactivity by using shallow refs, which track only the .value access for reactivity. This can be useful for optimizing performance with large objects or when the inner state is managed by an external library.

DOM Update Timing

When you mutate reactive state, Vue updates the DOM automatically. However, these updates are not applied synchronously. Vue buffers them until the next tick in the update cycle to ensure that each component updates only once, regardless of how many state changes occur.

To wait for the DOM update to complete after a state change, you can use the nextTick() global API:

import { nextTick } from 'vue'

async function increment() {
  count.value++
  await nextTick()
  // Now the DOM is updated
}

reactive() for Objects

Another way to declare reactive state is by using the reactive() API. This API creates a reactive object where all properties are reactive, including nested objects.

import { reactive } from 'vue'

const state = reactive({ count: 0 })

Usage in a template is similar to using refs:

<button @click="state.count++">
  {{ state.count }}
</button>

reactive() is especially useful for managing complex state structures, and it converts the object deeply. This means that changes to nested objects or arrays are automatically tracked and trigger reactivity updates.

Reactive Proxy vs. Original

It’s important to note that the value returned by reactive() is a Proxy of the original object, and they are not equal. To ensure consistent access to the proxy, it’s recommended to always use the proxied versions of your state.

const raw = {}
const proxy = reactive(raw)

console.log(proxy === raw) // false

When you call reactive() on the same object, it returns the same proxy, and calling reactive() on an existing proxy also returns that same proxy.

console.log(reactive(raw) === proxy) // true
console.log(reactive(proxy) === proxy) // true

This rule applies to nested objects as well, making sure that changes to nested properties are properly tracked and trigger reactivity updates.

Limitations of reactive()

While reactive() is a powerful tool for managing complex state, it has a few limitations:

Limited Value Types: reactive() only works for object types, such as objects, arrays, and collection types like Map and Set. It cannot be used with primitive types like strings, numbers, or booleans.

Cannot Replace Entire Object: You cannot easily replace an entire reactive object with another object, as Vue’s reactivity tracking works over property access. You must keep the same reference to the reactive object.

Not Destructure-Friendly: When you destructure a reactive object’s primitive type property into local variables or pass it into a function, you lose the reactivity connection. You must pass the entire object to retain reactivity.

Due to these limitations, it’s recommended to use ref() as the primary API for declaring reactive state in most cases.

Additional Ref Unwrapping Details

A ref is automatically unwrapped when accessed as a property of a reactive object. However, it does not unwrap when accessed as an element of a reactive array or a native collection type like Map.

Ref unwrapping in templates only applies if the ref is a top-level property in the template render context. Nested properties do not automatically unwrap in expressions.

When a ref is the final evaluated value of a text interpolation ({{ }}), it gets unwrapped. This is a convenience feature of text interpolation and is equivalent to {{ ref.value }}.

Understanding how to handle reactive state in Vue is essential for building dynamic and responsive applications. Whether you choose ref() or reactive(), Vue’s reactivity system provides the tools you need to create interactive user interfaces.

Vue Basic Todo List

Step 1: Setup Vue Project

Ensure you have Node.js version 16.0 or higher installed on your machine.

Open your command line or terminal and navigate to the directory where you want to create your Vue.js project.

Run the following command to create a Vue project using Vue CLI:

npm create vue@latest

Follow the prompts to configure your project. Choose the options that suit your needs, such as TypeScript support, Vue Router, etc.

Once the project is created, navigate to the project directory:

cd <your-project-name>

Install project dependencies:

npm install

Start the development server:

npm run dev

Your Vue project is now up and running. You can access it in your web browser at http://localhost:8080/.

Step 2: Create Todo Component

Create a new Vue component for your Todo app. You can use the Single-File Component (SFC) approach or define it as a plain JavaScript object. Here’s an example of an SFC:

<!-- src/components/TodoApp.vue -->
<template>
  <div>
    <h1>Todo App</h1>
    <!-- Todo list goes here -->
  </div>
</template>

<script setup>
  // Define reactive state and methods here
</script>

<style scoped>
  /* Add component-specific styles here */
</style>

Step 3: Define Reactive State

Inside the

import { ref } from 'vue';

const todos = ref([]);
const newTodo = ref('');

Implement methods to add, toggle, and remove Todo items. For example:

function addTodo() {
  if (newTodo.value.trim() === '') return;
  todos.value.push({ text: newTodo.value, completed: false });
  newTodo.value = '';
}

function toggleTodo(todo) {
  todo.completed = !todo.completed;
}

function removeTodo(index) {
  todos.value.splice(index, 1);
}

Step 4: Create Todo List

In your TodoApp component’s template, create a form for adding new Todo items:

<form @submit.prevent="addTodo">
  <input v-model="newTodo" placeholder="Add a new Todo" />
  <button type="submit">Add</button>
</form>

Below the form, iterate over the todos array and display each Todo item:

<ul>
  <li v-for="(todo, index) in todos" :key="index">
    <input type="checkbox" v-model="todo.completed" @change="toggleTodo(todo)" />
    {{ todo.text }}
    <button @click="removeTodo(index)">Delete</button>
  </li>
</ul>

Step 5: Test Your Todo App

Save your changes and ensure that your development server is running:

npm run dev

Open your web browser and go to http://localhost:8080/ to see your Todo app in action.

You should be able to add, mark as completed, and remove Todo items.

Congratulations! You’ve created a basic Todo app with Vue.js, defined reactive state, and implemented the necessary components and functionality. You can further enhance this app by adding features like local storage for persistence or additional styling for a better user experience.

Vue Composition API vs. Options API

Vue.js offers two different approaches to building components: the Composition API and the Options API. Both have their strengths and are suited to different use cases.

What is the Composition API?

The Composition API is a new and more flexible way to organize logic in Vue components. It encourages grouping code by functionality, making it easier to understand and reuse. It is particularly useful for larger components or applications with complex logic. The Composition API provides better support for TypeScript and is designed to enhance code maintainability.

What is the Options API?

The Options API is the traditional way to define Vue components. It relies on a set of predefined options to configure the component’s behavior. While it is straightforward and intuitive for simpler components and smaller applications, it may become less maintainable in larger and more complex projects.

How to Declare State

Composition API

In the Composition API, state is declared using the ref function. Here’s how to declare state:

import { ref } from 'vue';

const myState = ref(initialValue);

Options API

In the Options API, state is declared within the data function. Here’s how to declare state:

data() {
  return {
    myState: initialValue
  };
},

How to Use Props

Props are used to pass data from parent components to child components.

Composition API

In the Composition API, you can access props by using the defineProps function. Here’s how to use props:

import { defineProps } from 'vue';

const { prop1, prop2 } = defineProps(['prop1', 'prop2']);

Options API

In the Options API, props are defined in the props option. Here’s how to use props:

props: {
  prop1: String,
  prop2: Number
},

How to Define Methods

Methods are used to define functions that can mutate state and trigger updates in a component.

Composition API

In the Composition API, methods are defined as regular JavaScript functions. Here’s how to define methods:

function myMethod() {
  // Logic here
}

Options API

In the Options API, methods are defined within the methods option. Here’s how to define methods:

methods: {
  myMethod() {
    // Logic here
  }
},

How to Use Lifecycle Methods

Lifecycle methods are special functions that are called at different stages of a component’s lifecycle.

Composition API

In the Composition API, lifecycle hooks are imported from Vue and executed within the setup function. Here’s how to use lifecycle methods:

import { onMounted } from 'vue';

onMounted(() => {
  // Logic for the mounted hook
});

Options API

In the Options API, lifecycle methods are defined as options within the component. Here’s how to use lifecycle methods:

mounted() {
  // Logic for the mounted hook
},

Counter Component

Counter Component using Options API

<template>
  <div>
    <h2>Counter using Options API</h2>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    increment() {
      this.count++;
    },
  },
};
</script>

In this Options API example, we declare the count variable in the data function, and the increment method is defined within the methods option. The template displays the current count and includes a button to trigger the increment method.

Counter Component using Composition API

<template>
  <div>
    <h2>Counter using Composition API</h2>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const count = ref(0);

function increment() {
  count.value++;
}
</script>

In this Composition API example, we use the <script setup> syntax to declare the count variable using ref and define the increment function. The template is the same as the Options API example, displaying the current count and providing a button to increment it.

Vue Template Basics

A Vue.js template is typically defined within the <template> tag of a Vue component. It is where you describe the structure of your component’s HTML. Vue templates use regular HTML syntax with some additional features for handling dynamic data.

Here’s a simple Vue template:

<template>
  <div>
    <h1>{{ message }}</h1>
    <p>{{ description }}</p>
  </div>
</template>

In this example, {{ message }} and {{ description }} are expressions enclosed in double curly braces ({{ }}). These expressions are placeholders for dynamic data that will be rendered when the component is used.

Data Binding

Data binding is a fundamental concept in Vue.js that allows you to associate data in your component’s JavaScript with elements in the template. Vue provides two types of data binding:

Interpolation: You can use double curly braces ({{ }}) to interpolate data into the template. When the data changes, the template updates automatically.

<template>
  <p>{{ message }}</p>
</template>

Binding Attributes: You can bind HTML attributes to data using the v-bind directive (or its shorthand :). This is particularly useful for dynamic attributes, such as src, href, or class.

<template>
  <img :src="imageUrl" alt="Image" />
</template>

Directives

Directives are special tokens in the template that start with the v- prefix. They are used to apply special behavior to elements. Some commonly used directives include:

  • v-if: Conditional rendering based on a truthy expression.
  • v-for: Looping over an array to render a list of elements.
  • v-on (or @): Event handling to listen for DOM events.
  • v-bind (or :): Binding HTML attributes to data.
  • v-model: Two-way data binding for form input elements.

Here’s an example of using v-for to iterate over an array:

<template>
  <ul>
    <li v-for="item in items" :key="item.id">{{ item.name }}</li>
  </ul>
</template>

Event Handling

Vue allows you to handle DOM events using the v-on directive or its shorthand @. You can specify the event you want to listen for and the method to call when the event occurs.

<template>
  <button @click="handleClick">Click me</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      // Handle the click event
    },
  },
};
</script>

Filters

Filters are used to format and transform data within templates. You can use built-in filters or create custom ones. Filters are applied using the | symbol.

<template>
  <p>{{ message | capitalize }}</p>
</template>

<script>
export default {
  filters: {
    capitalize(value) {
      if (!value) return '';
      return value.charAt(0).toUpperCase() + value.slice(1);
    },
  },
};
</script>

Template Expressions

In Vue templates, you can use JavaScript expressions within double curly braces to compute values or perform operations.

<template>
  <p>Total: {{ price * quantity }}</p>
</template>

Template References

You can reference elements in the template using the ref attribute, allowing you to access and manipulate DOM elements directly.

<template>
  <input ref="myInput" />
</template>

<script>
export default {
  mounted() {
    // Access the input element
    this.$refs.myInput.focus();
  },
};
</script>

These are the key aspects of Vue’s templating syntax. Vue templates are powerful and expressive, making it easy to build dynamic and interactive user interfaces while maintaining a clean separation of concerns between the template and the JavaScript logic.