Table of Contents
- What is Vue.js?
- Why Vue.js for Beginners?
- Setting Up Your Vue.js Environment
- Core Concepts
- Vue Router: Adding Navigation
- State Management with Pinia
- Conclusion: Next Steps
- References
What is Vue.js?
Vue.js (pronounced “view”) is an open-source JavaScript framework for building user interfaces (UIs) and single-page applications. At its core, Vue focuses on the view layer of your application, meaning it handles how data is displayed and interacted with in the browser.
What makes Vue unique is its “progressive” nature: you can integrate it into existing projects incrementally (e.g., adding Vue to a small part of a jQuery app) or use it to build full-fledged SPAs with tools like Vue Router (for navigation) and Pinia (for state management).
Vue was created by Evan You, a former Google engineer who worked on AngularJS. Frustrated by Angular’s complexity, he set out to build a framework that combined the best parts of Angular (two-way data binding, directives) with the simplicity of React (component-based architecture). The result? Vue.js, which has since grown into one of the most popular JavaScript frameworks, with a thriving community and ecosystem.
Why Vue.js for Beginners?
If you’re new to JavaScript frameworks, Vue.js is an excellent starting point. Here’s why:
- Simplicity: Vue’s syntax is intuitive and HTML-based, making it easy to learn if you already know HTML, CSS, and basic JavaScript.
- Gentle Learning Curve: Unlike Angular (which has a steeper learning curve) or React (which requires learning JSX upfront), Vue lets you start small and scale up.
- Comprehensive Documentation: Vue’s official docs are widely praised for being clear, well-organized, and beginner-friendly.
- Reactivity System: Vue automatically updates the DOM when your data changes, so you don’t have to manually manipulate the DOM (bye-bye,
document.getElementById!). - Flexibility: Use Vue’s template syntax (HTML-based) or render functions (JavaScript-based) depending on your needs.
- Strong Community Support: A large community means plenty of tutorials, plugins, and third-party tools to help you troubleshoot.
Setting Up Your Vue.js Environment
Before diving into code, let’s set up your development environment. We’ll cover two options: a quick start with CDN (no installation required) and a more robust setup with Vite (the recommended tool for production projects).
Option 1: Quick Start with CDN
For small projects or experimentation, you can include Vue directly via a CDN (Content Delivery Network). Add this script tag to your HTML file:
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
Now you can use Vue in a simple HTML file. Create an index.html file and add the following:
<!DOCTYPE html>
<html>
<head>
<title>Vue Quick Start</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
// Create a Vue app instance
const { createApp } = Vue;
createApp({
data() {
return {
message: "Hello, Vue!"
}
}
}).mount('#app'); // Mount the app to the DOM element with id "app"
</script>
</body>
</html>
Open this file in your browser, and you’ll see “Hello, Vue!” displayed. Congrats—you’ve built your first Vue app!
Option 2: Using Vite (Recommended)
For larger projects, we recommend using Vite (a fast build tool) to set up a Vue project. Vite provides features like hot module replacement (HMR), optimized builds, and support for modern JavaScript.
Step 1: Install Node.js
Vite requires Node.js (v14.18+ or v16+). Download it from nodejs.org. To check if Node is installed, run:
node -v # Should output v14.18.0 or higher
npm -v # Should output v6.14.0 or higher
Step 2: Create a Vite Project
Run the following command in your terminal to create a new Vue project:
npm create vite@latest my-vue-app -- --template vue
my-vue-app: The name of your project (change it to something creative!).--template vue: Specifies we want a Vue project.
Step 3: Navigate to the Project and Install Dependencies
cd my-vue-app
npm install # Installs project dependencies
Step 4: Run the Development Server
npm run dev
Vite will start a local server (usually at http://localhost:5173). Open this URL in your browser, and you’ll see a default Vue welcome page.
Project Structure
Let’s briefly explore the folder structure of your Vite Vue project:
my-vue-app/
├── node_modules/ # Dependencies (auto-generated)
├── public/ # Static assets (e.g., images, favicon)
├── src/ # Your code lives here!
│ ├── assets/ # CSS, images, etc.
│ ├── components/ # Reusable Vue components
│ ├── App.vue # Root component
│ └── main.js # Entry point (mounts the app)
├── .gitignore # Files to ignore in Git
├── index.html # HTML entry point
├── package.json # Project metadata and scripts
└── vite.config.js # Vite configuration
The src/App.vue file is your app’s root component. Let’s modify it to display a custom message:
<!-- src/App.vue -->
<template>
<h1>Hello from my first Vue app! 🚀</h1>
</template>
Save the file, and your browser will automatically update (thanks to Vite’s HMR). Cool, right?
Core Concepts
Now that your environment is set up, let’s explore Vue’s core concepts—the building blocks of any Vue app.
The Vue Instance
Every Vue app starts with a Vue instance (or “app instance”), created using createApp. This instance serves as the root of your application and manages data, methods, and component registration.
In src/main.js, you’ll see:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
Here, createApp(App) creates an app instance with App.vue as the root component, and .mount('#app') attaches it to the DOM element with id app (defined in index.html).
Templates and Directives
Vue uses templates to define the structure of your UI. Templates are HTML-based and can include Vue-specific features like interpolation and directives.
Interpolation
Use double curly braces {{ }} to insert data into your template. For example:
<template>
<p>{{ message }}</p> <!-- Displays the value of `message` -->
</template>
<script>
export default {
data() {
return {
message: "Hello, interpolation!"
}
}
}
</script>
Directives
Directives are special attributes prefixed with v- that apply reactive behavior to the DOM. Let’s cover the most common ones:
-
v-bind: Binds an HTML attribute to a data property. Shorthand::.<template> <a v-bind:href="linkUrl">Visit Vue Docs</a> <!-- Shorthand --> <img :src="imageUrl" alt="Vue logo"> </template> <script> export default { data() { return { linkUrl: "https://vuejs.org/guide/introduction.html", imageUrl: "/src/assets/vue.svg" } } } </script> -
v-if/v-else: Conditionally renders elements.<template> <p v-if="isLoggedIn">Welcome back! 👋</p> <p v-else>Please log in. 🚪</p> </template> <script> export default { data() { return { isLoggedIn: false // Change to true to see the "Welcome" message } } } </script> -
v-for: Renders a list of items.<template> <ul> <li v-for="(item, index) in items" :key="index"> {{ index + 1 }}. {{ item }} </li> </ul> </template> <script> export default { data() { return { items: ["Learn Vue", "Build an app", "Profit!"] } } } </script>Note: Always use
:keywithv-forto help Vue track list items efficiently. -
v-on: Listens to DOM events (e.g., clicks, input). Shorthand:@.<template> <button @click="count++">Click me!</button> <p>You clicked {{ count }} times.</p> </template> <script> export default { data() { return { count: 0 } } } </script>
Reactivity: How Vue Updates the DOM
One of Vue’s most powerful features is its reactivity system. When you modify data in Vue, the DOM automatically updates to reflect those changes—no manual DOM manipulation required!
Vue achieves this by converting your data properties into reactive getters and setters during initialization. When a property is accessed, Vue tracks the component using it; when the property is modified, Vue triggers updates for all dependent components.
Example:
<template>
<p>{{ message }}</p>
<button @click="updateMessage">Change Message</button>
</template>
<script>
export default {
data() {
return {
message: "Hello, reactivity!"
}
},
methods: {
updateMessage() {
this.message = "Reactivity is awesome! 🎉"; // Updates the DOM automatically
}
}
}
</script>
Pro Tip: For reactivity to work, data properties must be declared in the data function upfront. If you need to add a property dynamically later, use this.$set(this.object, 'newProperty', value) (or Vue.set globally).
Components: Building Blocks of Vue Apps
Components are reusable, self-contained pieces of UI. Think of them as custom HTML elements that you can use throughout your app. For example, a Button, Card, or TodoItem component.
Creating a Component
In Vue, components are defined in .vue files (called “single-file components” or SFCs), which combine template, script, and style in one file.
Let’s create a Greeting.vue component in src/components/:
<!-- src/components/Greeting.vue -->
<template>
<div class="greeting">
<h2>Hello, {{ name }}! 👋</h2>
</div>
</template>
<script>
export default {
data() {
return {
name: "Friend" // Default name
}
}
}
</script>
<style scoped>
/* scoped: styles only apply to this component */
.greeting {
color: #42b983; /* Vue's brand color */
padding: 1rem;
border: 1px solid #eee;
border-radius: 4px;
}
</style>
Using a Component
To use Greeting.vue in App.vue, import it and register it:
<!-- src/App.vue -->
<template>
<h1>My Vue App</h1>
<Greeting /> <!-- Use the component -->
</template>
<script>
import Greeting from './components/Greeting.vue'; // Import the component
export default {
components: {
Greeting // Register the component locally
}
}
</script>
Save the files, and you’ll see the greeting displayed in your browser.
Props: Passing Data to Child Components
Props let you pass data from a parent component to a child component. This makes components dynamic and reusable.
Step 1: Define Props in the Child Component
Update Greeting.vue to accept a name prop instead of hardcoding it:
<!-- src/components/Greeting.vue -->
<template>
<div class="greeting">
<h2>Hello, {{ name }}! 👋</h2>
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true, // Parent must provide this prop
default: "Guest" // Fallback if not provided
}
}
}
</script>
Step 2: Pass Props from the Parent
In App.vue, pass a name prop to Greeting:
<!-- src/App.vue -->
<template>
<h1>My Vue App</h1>
<Greeting name="Alice" /> <!-- Pass prop -->
<Greeting name="Bob" /> <!-- Reuse component with different data -->
</template>
Now you’ll see two greetings: “Hello, Alice!” and “Hello, Bob!”. Cool—your component is reusable!
Events: Child-to-Parent Communication
Props pass data down, but what if a child component needs to send data up to the parent (e.g., a button click in a child should trigger an action in the parent)? Use events!
Step 1: Emit an Event from the Child
Let’s add a button to Greeting.vue that emits an event when clicked:
<!-- src/components/Greeting.vue -->
<template>
<div class="greeting">
<h2>Hello, {{ name }}! 👋</h2>
<button @click="sayHi">Say Hi</button>
</div>
</template>
<script>
export default {
props: ['name'],
methods: {
sayHi() {
// Emit an event named 'greet' with a message
this.$emit('greet', `Hi from ${this.name}!`);
}
}
}
</script>
Step 2: Listen for the Event in the Parent
In App.vue, listen for the greet event and handle it with a method:
<!-- src/App.vue -->
<template>
<h1>My Vue App</h1>
<Greeting
name="Alice"
@greet="handleGreet" <!-- Listen for 'greet' event -->
/>
<p v-if="lastGreeting">{{ lastGreeting }}</p>
</template>
<script>
import Greeting from './components/Greeting.vue';
export default {
components: { Greeting },
data() {
return {
lastGreeting: null
}
},
methods: {
handleGreet(message) {
this.lastGreeting = message; // Update data with the emitted message
}
}
}
</script>
Click the “Say Hi” button, and you’ll see “Hi from Alice!” displayed below the greeting. Now your components can communicate bidirectionally!
Lifecycle Hooks
Vue components go through a series of stages during their existence: creation, mounting, updating, and destruction. Lifecycle hooks are functions that let you run code at specific stages.
Common hooks include:
created: Runs after the component is initialized (data is set up, but DOM not yet mounted).mounted: Runs after the component is mounted to the DOM (good for DOM manipulation or API calls).updated: Runs after the component’s data changes and the DOM updates.unmounted: Runs after the component is removed from the DOM (good for cleanup).
Example: Fetch data when the component mounts:
<template>
<div>
<h2>Random Fact</h2>
<p v-if="fact">{{ fact }}</p>
<p v-else>Loading fact...</p>
</div>
</template>
<script>
export default {
data() {
return {
fact: null
}
},
mounted() {
// Fetch a random fact from an API when the component mounts
fetch('https://catfact.ninja/fact')
.then(response => response.json())
.then(data => {
this.fact = data.fact; // Update data, which updates the DOM
});
}
}
</script>
Vue Router: Adding Navigation
Most apps need multiple pages (e.g., Home, About, Contact). Vue Router is the official routing library for Vue.js, enabling client-side navigation (no page reloads!).
Installing Vue Router
In your project, run:
npm install vue-router@4 # Vue Router 4 is compatible with Vue 3
Setting Up Routes
- Create a
routerfolder insrc/and addindex.js:
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
// Define routes
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
];
// Create router instance
const router = createRouter({
history: createWebHistory(), // Uses HTML5 history mode (no hash in URL)
routes
});
export default router;
- Create
Home.vueandAbout.vueinsrc/views/(views are components for full pages):
<!-- src/views/Home.vue -->
<template>
<div class="home">
<h1>Welcome to the Home Page! 🏠</h1>
</div>
</template>
<!-- src/views/About.vue -->
<template>
<div class="about">
<h1>About Us 📝</h1>
<p>We love Vue.js!</p>
</div>
</template>
- Update
src/main.jsto use the router:
import { createApp } from 'vue';
import App from './App.vue';
import router from './router'; // Import the router
createApp(App)
.use(router) // Use the router
.mount('#app');
- Update
App.vueto include navigation links and a route view:
<!-- src/App.vue -->
<template>
<div id="app">
<!-- Navigation links -->
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<!-- Route view: where the current page component is rendered -->
<router-view />
</div>
</template>
<style>
/* Style navigation links */
nav {
padding: 2rem;
text-align: center;
}
router-link {
margin: 0 1rem;
text-decoration: none;
color: #333;
}
router-link.router-link-exact-active {
color: #42b983; /* Highlight active link */
font-weight: bold;
}
</style>
Now, run npm run dev and click the links—you’ll navigate between pages without reloading!
State Management with Pinia
As your app grows, you’ll need to share state (data) across components (e.g., user authentication status, a shopping cart). Pinia is Vue’s official state management library (replacing Vuex) and is simpler to use.
Installing Pinia
npm install pinia
Creating a Store
Stores are containers for shared state and logic. Let’s create a counter store:
- Update
src/main.jsto use Pinia:
import { createApp } from 'vue';
import { createPinia } from 'pinia'; // Import Pinia
import App from './App.vue';
import router from './router';
const app = createApp(App);
app.use(createPinia()); // Use Pinia
app.use(router);
app.mount('#app');
- Create a
storesfolder insrc/and addcounter.js:
// src/stores/counter.js
import { defineStore } from 'pinia';
// Define a store with id 'counter'
export const useCounterStore = defineStore('counter', {
// State: shared data
state: () => ({
count: 0
}),
// Actions: functions to modify state
actions: {
increment() {
this.count++;
},
decrement() {
this.count--;
},
reset() {
this.count = 0;
}
},
// Getters: computed properties for state
getters: {
doubleCount: (state) => state.count * 2
}
});
Using the Store in a Component
Let’s use the counter store in Home.vue:
<!-- src/views/Home.vue -->
<template>
<div class="home">
<h1>Counter: {{ counterStore.count }}</h1>
<p>Double Count: {{ counterStore.doubleCount }}</p>
<button @click="counterStore.increment">+</button>
<button @click="counterStore.decrement">-</button>
<button @click="counterStore.reset">Reset</button>
</div>
</template>
<script>
import { useCounterStore } from '../stores/counter';
export default {
setup() {
const counterStore = useCounterStore(); // Access the store
return { counterStore };
}
}
</script>
Now the counter state is shared across any component that uses useCounterStore—try adding it to About.vue too!
Conclusion: Next Steps
Congratulations! You’ve learned the basics of Vue.js, including:
- Setting up a Vue project with Vite
- Core concepts: templates, directives, reactivity, components, props, events, and lifecycle hooks
- Routing with Vue Router
- State management with Pinia
To巩固 (solidify) your skills, try building a small project:
- Todo App: Create a list of todos with add/delete functionality.
- Weather Dashboard: Use an API to fetch and display weather data.
- Profile Card: Build a reusable card component with props for name, bio, and avatar.
Remember, practice is key! Refer to the official docs when you get stuck, and don’t hesitate to ask the Vue community for help.
References
- Vue.js Official Documentation
- Vue Router Documentation
- Pinia Documentation
- Vite Documentation
- Vue School (Free Tutorials)
- Vue GitHub Repository
Happy coding! 🚀