背景图
Vue Notes 1: Back to the Basics

2026年02月22日 作者头像 作者头像 ArnoX 编辑

Vue.jpg


Getting Comfortable with Vue 3

Lately, with a bit of unexpected free time (which, admittedly, is a slightly sad situation...), I’ve been playing around with a few small Vue projects. Rather than treating this purely as practice, I decided to use this space to document parts of my earlier Vue learning notes.

This blog is not really about learning Vue from scratch, but more about revisiting the fundamentals, clarifying concepts, and occasionally rediscovering patterns that remain surprisingly relevant in real-world development. Perhaps in future posts, this series may evolve into deeper discussions on design decisions, abstractions, or implementation strategies. We’ll see where it goes.

Vue is often described as a progressive UI framework, but what that really means becomes clearer once you compare it with traditional frontend development.

In a vanilla JavaScript workflow, updating the UI usually involves directly querying and mutating DOM elements:

const ele = document.querySelector("#input");
ele.value = "Hello";

This works, but as applications grow, this style quickly turns into a maintenance headache. State lives in scattered places, DOM updates become fragile, and UI logic gets tightly coupled with document
structure.

Vue approaches the problem differently. Instead of manually manipulating DOM nodes, you describe your interface as a composition of reactive components.


Thinking in Components

In Vue, a component is essentially a self-contained UI unit with three clearly separated parts:

<template>
  <h1>{{ post.title }}</h1>
  <p>{{ post.summary }}</p>
</template>

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

const post = ref({
  title: "Understanding Vue Reactivity",
  summary: "Reactivity is where Vue really shines."
});
</script>

<style scoped>
h1 {
  font-weight: 600;
}
</style>

Rather than asking "how do I update this DOM node?", the question becomes:

"What should the UI look like when the state changes?"

Vue handles the DOM updates automatically.


Why Isolation Matters

One of the underrated benefits of Vue's component model is state isolation.

Each component maintains its own reactive scope. Data does not leak unless explicitly passed:

<script setup>
posts; // Not accessible unless provided
</script>

This design prevents accidental coupling between unrelated parts of the UI, something that frequently causes subtle bugs in large applications.


Bootstrapping a Vue Project with Vite

For modern Vue development, Vite is the default choice.

Creating a project is refreshingly simple:

npm init vue@latest

Run the development server:

npm install
npm run dev

Vite’s instant startup and hot module replacement drastically improve the feedback loop during development, especially noticeable when working on UI-heavy features.


Binding Data to Templates

Vue's template syntax is intentionally minimal.

Interpolation:

{{ post.title }}

Attribute binding:

<a :href="post.link">Read more</a>

Example:

<template>
  <article>
    <h2>
      <a :href="post.link">{{ post.title }}</a>
    </h2>
    <p>{{ post.content }}</p>
  </article>
</template>

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

const post = ref({
  title: "Vue 3 Composition API",
  content: "The Composition API introduces a more flexible logic structure.",
  link: "/posts/vue-3"
});
</script>

Conditional Rendering

Conditional UI logic becomes declarative:

<footer v-if="post.content.length > 80">
  <button>Continue Reading</button>
</footer>

Instead of toggling visibility manually, rendering naturally follows state.


Rendering Lists

Reactive arrays integrate directly with rendering:

<div v-for="post in posts" :key="post.id">
  <h3>{{ post.title }}</h3>
</div>
<script setup>
import { ref } from "vue";

const posts = ref([
  { id: 1, title: "Vue Basics", content: "..." },
  { id: 2, title: "Reactivity Deep Dive", content: "..." },
  { id: 3, title: "Component Patterns", content: "..." }
]);
</script>

Using a stable key is critical here. It allows Vue’s virtual DOM diffing algorithm to work efficiently rather than re-rendering unnecessarily.


Computed Properties

Whenever UI values depend on reactive data, computed keeps logic clean:

<script setup>
import { computed } from "vue";

const totalPosts = computed(() => posts.value.length);
</script>

This avoids duplicating state or introducing synchronization bugs.


Handling Events

Event handling stays close to the template:

<button @click="toggleStats">
  {{ showStats ? "Hide" : "Show" }} Stats
</button>
const showStats = ref(true);

function toggleStats() {
  showStats.value = !showStats.value;
}

Simple, predictable, and easy to trace.


Form Handling with v-model

Two-way binding reduces boilerplate:

<input v-model="form.title" />
<textarea v-model="form.content"></textarea>
const form = ref({
  title: "",
  content: "",
  link: ""
});

Vue synchronizes input state without manual listeners or DOM queries.


Component Composition with Props

Breaking UI into reusable units:

<script setup>
defineProps(["title", "content", "link"]);
</script>

Example:

<PostCard v-for="post in posts" v-bind="post" />

v-bind="post" keeps templates concise and scalable.


Slots: Flexible Component Design

Slots enable composable UI patterns:

<slot></slot>

This pattern becomes especially powerful when designing layout systems or design libraries.


Lifecycle Hooks

Lifecycle hooks help manage side effects predictably:

import { onMounted, ref } from "vue";

const views = ref(0);

onMounted(() => {
  fetchViewCount();
});

Lifecycle hooks prevent premature side effects and keep component logic deterministic.


Custom Events

Child-to-parent communication remains structured:

defineEmits(["titleClick"]);
<a @click.prevent="$emit('titleClick', title)">
<PostCard @titleClick="handleClick" />

To be continued...