Vue组件开发与通信详解
深入理解Vue组件
Vue.js的组件化开发是现代前端开发的重要组成部分,它使得代码更加模块化、易于维护和复用。本文将详细探讨Vue组件的基础知识及其高级应用。
组件基础
什么是组件?
<!-- 组件就像自定义HTML元素 -->
<user-profile
:userinfo="currentUser"
:editable="true"
@save="handleSave"
/>
// 内部包含:
// 1. 模板 (HTML结构)
// 2. 脚本 (JavaScript行为)
// 3. 样式 (CSS样式)
| 特性 | HTML元素 | Vue组件 |
|---|---|---|
| 可复用性 | 低 | 高 |
| 封装性 | 无 | 强 |
| 数据绑定 | 不支持 | 支持 |
| 事件处理 | 基础 | 丰富 |
| 生命周期 | 无 | 完整 |
| 样式隔离 | 无 | 支持 |
组件注册
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 全局注册组件
app.component('MyButton', {
template: '<button @click="onClick">点击我</button>',
methods: {
onClick() {
this.$emit('click')
}
}
})
// 局部注册组件
<template>
<div>
<LocalCounter />
<SpecialButton />
</div>
</template>
<script>
import LocalCounter from './LocalCounter.vue'
import SpecialButton from './SpecialButton.vue'
export default {
components: {
LocalCounter,
CustomButton: SpecialButton
}
}
</script>
单文件组件(SFC)
<template>
<div class="user-card">
<img :src="avatar" :alt="name" class="avatar" />
<div class="user-info">
<h3>{{ name }}</h3>
<p>{{ email }}</p>
</div>
<button @click="follow" class="follow-btn">
{{ isFollowing ? '取消关注' : '关注' }}
</button>
</div>
</template>
<script>
export default {
props: ['userId', 'name', 'email', 'avatar', 'initialFollowing'],
data() {
return {
isFollowing: this.initialFollowing
}
},
methods: {
follow() {
if (this.isFollowing) {
// 取消关注逻辑
} else {
// 关注逻辑
}
}
}
}
</script>
<style scoped>
.user-card {
padding: 16px;
background: white;
transition: box-shadow 0.3s ease;
}
</style>
组件通信
父传子:Props
<!-- ParentComponent.vue -->
<template>
<ChildComponent title="用户列表" :items="userList" />
</template>
<script>
export default {
data() {
return {
userList: ['Alice', 'Bob']
}
}
}
</script>
<!-- ChildComponent.vue -->
<template>
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</template>
<script>
export default {
props: ['title', 'items']
}
</script>
子传父:$emit
<!-- ChildComponent.vue -->
<template>
<button @click="increment">增加</button>
</template>
<script>
export default {
emits: ['increment'],
methods: {
increment() {
this.$emit('increment')
}
}
}
</script>
<!-- ParentComponent.vue -->
<template>
<ChildComponent @increment="count++" />
</template>
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
插槽 Slot
默认插槽
<!-- BaseLayout.vue -->
<template>
<header>
<slot>默认标题</slot>
</header>
<main>
<slot>默认内容</slot>
</main>
</template>
<!-- 使用组件 -->
<template>
<BaseLayout>
<template #default>
<h2>主要内容</h2>
</template>
</BaseLayout>
</template>
具名插槽
<!-- CardComponent.vue -->
<template>
<header>
<slot name="header">默认标题</slot>
</header>
<footer>
<slot name="footer"><button>默认按钮</button></slot>
</footer>
</template>
<!-- 使用组件 -->
<template>
<CardComponent>
<template #header><h3>用户信息</h3></template>
<template #footer><button>编辑</button></template>
</CardComponent>
</template>
动态组件和异步组件
动态组件
<template>
<component :is="currentTab"></component>
</template>
<script>
import HomePage from './HomePage.vue'
import AboutPage from './AboutPage.vue'
export default {
data() {
return {
currentTab: 'HomePage'
}
},
components: {
HomePage,
AboutPage
}
}
</script>
异步组件加载
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent(() => import('./HeavyComponent.vue'))
export default {
components: {
AsyncComponent
}
}