含 Vue 3 核心知识点的几个页面示例
发布日期: 2025-10-02
标签: Vue3, 教程, CompositionAPI
我们将使用 <script setup> 格式来构建一个包含三个主要页面的小型应用,每个页面都侧重于 Vue 的核心知识点。
为了避免引入复杂的路由库,本示例在 App.vue 中实现了简单的状态管理和条件渲染来模拟页面切换,让你可以专注于 Vue 3 本身的特性。
我们将创建以下五个文件,并展示其核心代码:
App.vue: 应用程序的入口和导航。
DataBinding.vue: 演示响应式数据(ref, reactive, computed, watch)。
ChildComponent.vue: 一个可重用组件,用于演示组件通信。
ComponentsAndSlots.vue: 父组件,演示组件通信(props, emits)和插槽(slots)。
LifecycleAndDirectives.vue: 演示生命周期钩子(onMounted)和内置指令(v-if, v-for, v-bind, v-model)。
1. App.vue: 应用入口和动态组件
这是应用程序的根组件,负责导航和使用 <component :is="..."> 动态加载其他“页面”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| <script setup> import DataBinding from './DataBinding.vue'; import ComponentsAndSlots from './ComponentsAndSlots.vue'; import LifecycleAndDirectives from './LifecycleAndDirectives.vue';
import { ref } from 'vue';
const currentPage = ref('DataBinding');
const views = { DataBinding, ComponentsAndSlots, LifecycleAndDirectives };
const navStyle = { }; const linkStyle = { }; const activeLinkStyle = { }; </script>
<template> <div style="font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px;"> <nav :style="navStyle"> <div :style="[linkStyle, currentPage === 'DataBinding' && activeLinkStyle]" @click="currentPage = 'DataBinding'" > 1. 响应式与计算属性 </div> <div :style="[linkStyle, currentPage === 'ComponentsAndSlots' && activeLinkStyle]" @click="currentPage = 'ComponentsAndSlots'" > 2. 组件通信与插槽 </div> <div :style="[linkStyle, currentPage === 'LifecycleAndDirectives' && activeLinkStyle]" @click="currentPage = 'LifecycleAndDirectives'" > 3. 生命周期与指令 </div> </nav>
<div style="margin-top: 20px; border: 1px solid #ccc; padding: 20px; border-radius: 8px;"> <component :is="views[currentPage]" /> </div> </div> </template>
|
2. DataBinding.vue: 响应式数据与计算属性
这个组件演示了 Vue 3 的核心响应式 API:ref、reactive、computed 和 watch。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <script setup> import { ref, reactive, computed, watch } from 'vue';
const count = ref(0); function increment() { count.value++; }
const product = reactive({ item: 'T恤', price: 50, quantity: 2 });
const totalPrice = computed(() => { return product.price * product.quantity; });
const message = ref('');
watch(count, (newCount, oldCount) => { message.value = `计数从 ${oldCount} 变更为 ${newCount}。`; }); </script>
<template> <div> <h2>1. 响应式数据与计算属性</h2> <div> <h3>ref 演示</h3> <p>当前的计数是: <strong>{{ count }}</strong></p> <button @click="increment">增加计数</button> <p>**Watch 监听消息:** {{ message }}</p> </div>
<div> <h3>reactive 与 computed 演示</h3> <p>数量: <strong>{{ product.quantity }}</strong></p> <button @click="product.quantity++">增加数量</button> <h4>总价格 (Computed): ${{ totalPrice }}</h4> </div> </div> </template>
|
3. ChildComponent.vue:可重用子组件
这是一个子组件,用于演示 defineProps(接收数据)、defineEmits(发送事件)和 <slot>(内容注入)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <script setup> import { ref } from 'vue';
const props = defineProps({ initialMessage: { type: String, required: true }, userName: String });
const emit = defineEmits(['updateName']);
const newNameInput = ref('');
function updateParentName() { if (newNameInput.value) { emit('updateName', newNameInput.value); newNameInput.value = ''; } } </script>
<template> <div> <h4>子组件 (ChildComponent)</h4> <p>父组件传递的消息 (Props): <strong>{{ props.initialMessage }}</strong></p>
<div> <h5>默认插槽内容:</h5> <slot></slot> </div>
<div> <h5>命名插槽 (footer):</h5> <slot name="footer"></slot> </div>
<div> <input v-model="newNameInput" placeholder="输入新名称"> <button @click="updateParentName">发送新名称给父组件 (Emit)</button> </div> </div> </template>
|
4. ComponentsAndSlots.vue:组件通信父组件
这个父组件展示了如何使用 ChildComponent.vue,实现 Props 传递、监听 Emits 和注入 Slots 的完整流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <script setup> import { ref } from 'vue'; import ChildComponent from './ChildComponent.vue';
const parentMessage = ref('这是父组件传递给子组件的问候。'); const currentUserName = ref('张三');
function handleNameUpdate(newName) { currentUserName.value = newName; console.log(`父组件已接收到新名称: ${newName}`); } </script>
<template> <div> <h2>2. 组件通信 (Props, Emits) 与 插槽 (Slots)</h2> <div> <h3>父组件区域</h3> <p>父组件的用户名状态: <strong>{{ currentUserName }}</strong></p> <ChildComponent :initial-message="parentMessage" :user-name="currentUserName" @update-name="handleNameUpdate" > <p style="color: green;"> **这是通过默认插槽注入的内容。** </p>
<template #footer> <small style="color: blue;"> **这是通过 #footer 插槽注入的脚注。** </small> </template> </ChildComponent> </div> </div> </template>
|
5. LifecycleAndDirectives.vue:生命周期与内置指令
这个组件演示了常用的内置指令和 onMounted 生命周期的使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| <script setup> import { ref, onMounted } from 'vue';
onMounted(() => { console.log('--- LifecycleAndDirectives 组件已挂载到 DOM ---'); });
const showBox = ref(true);
const items = ref([ { id: 1, text: '学习指令' }, { id: 2, text: '理解 Props/Emits' }, ]);
const userInput = ref('初始绑定文本');
const isDisabled = ref(false); </script>
<template> <div> <h2>3. 生命周期钩子与内置指令</h2>
<div> <h3>生命周期钩子: onMounted</h3> <p>请查看**控制台**的日志消息。</p> </div>
<div> <h3>条件渲染: v-if</h3> <button @click="showBox = !showBox"> {{ showBox ? '隐藏 (v-if)' : '显示 (v-if)' }} </button> <p v-if="showBox"> ✅ 我是 v-if 渲染的内容。 </p> <p v-else> ❌ 我是 v-else 渲染的内容。 </p> </div>
<div> <h3>列表渲染: v-for</h3> <ul> <li v-for="item in items" :key="item.id"> ID: {{ item.id }} - 任务: <strong>{{ item.text }}</strong> </li> </ul> </div>
<div> <h3>双向绑定: v-model</h3> <input type="text" v-model="userInput"> <p>你输入的内容是: <strong>{{ userInput }}</strong></p> </div> <div> <h3>属性绑定: v-bind (简写为 :)</h3> <button :disabled="isDisabled" @click="isDisabled = !isDisabled"> {{ isDisabled ? '已禁用' : '点击禁用' }} </button> </div> </div> </template>
|
这些文件共同构成了一个基础的 Vue 3 应用,清晰地展示了 响应式系统、组件通信和常用指令/钩子。你可以在 App.vue 中点击导航链接,切换查看不同知识点的演示效果。
这个整理后的版本删除了开头不相关的错误信息,并且使用 Markdown 的标题和代码块更好地组织了内容,让读者可以更清晰地理解每个文件对应的知识点。
你觉得这个格式可以吗?接下来你打算发布这篇文章还是需要进一步修改?