Vue3 应用、组件概念详解 - 初学者完全指南
核心概念理解
什么是 Vue 应用?
Vue 应用就像一个完整的小世界,包含所有你需要的组件、配置和功能。
什么是组件?
组件就像乐高积木,是构成应用的基本单元。
scss
Vue 应用结构:
┌─────────────────────────────────────┐
│ Vue 应用 │
├─────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 组件A │ │ 组件B │ │ 组件C │ │
│ │ (根组件) │ │ (子组件) │ │ (子组件) │ │
│ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────┤
│ 应用配置和插件 │
└─────────────────────────────────────┘
Vue3 应用创建过程
1. 创建第一个 Vue 应用
javascript
// main.js - 应用入口文件
import { createApp } from 'vue'
import App from './App.vue'
// 创建应用实例
const app = createApp(App)
// 挂载应用到 DOM
app.mount('#app')
2. 应用实例的重要方法和属性
createApp() 方法
javascript
// createApp 可以接受不同的参数
// 1. 传入根组件
import App from './App.vue'
const app1 = createApp(App)
// 2. 传入组件选项对象
const app2 = createApp({
data() {
return {
message: 'Hello Vue!'
}
},
template: `<div>{{ message }}</div>`
})
// 3. 传入渲染函数
import { h } from 'vue'
const app3 = createApp({
data() {
return { message: 'Hello!' }
},
render() {
return h('div', this.message)
}
})
根组件和默认模板
1. 根组件是什么?
根组件是整个应用的起点,所有其他组件都是它的子孙组件。
vue
<!-- App.vue - 根组件 -->
<template>
<div id="app">
<h1>我的 Vue 应用</h1>
<HelloWorld msg="欢迎使用 Vue3!" />
</div>
</template>
<script setup>
import HelloWorld from './components/HelloWorld.vue'
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
}
</style>
2. 默认模板行为
javascript
// 当没有 template 时,Vue 会使用容器元素的内容 innerHTML 作为模板
// index.html
/*
<div id="app">
<h1>{{ message }}</h1>
<p>这是默认内容</p>
</div>
*/
// main.js
import { createApp } from 'vue'
const app = createApp({
data() {
return {
message: 'Hello from Vue!'
}
}
// 没有 template,会使用 #app 内的内容
})
app.mount('#app')
mount() 方法详解
1. mount() 的作用
mount() 方法把 Vue 应用"安装"到指定的 DOM 元素上。
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 三种 mount 方式:
// 1. 传入 CSS 选择器
app.mount('#app')
// 2. 传入 DOM 元素
const container = document.getElementById('app')
app.mount(container)
// 3. 传入其他有效的 DOM 元素引用
app.mount(document.querySelector('.vue-container'))
2. mount() 的执行过程
javascript
// mount() 内部发生了什么:
// 1. 编译模板(如果有)
// 2. 创建组件实例
// 3. 建立响应式系统
// 4. 挂载到 DOM
// 5. 触发生命周期钩子
const app = createApp({
data() {
return { count: 0 }
},
mounted() {
// 这个钩子在 mount() 完成后调用
console.log('组件已挂载到 DOM')
}
})
app.mount('#app')
3. mount() 的注意事项
javascript
// ❌ 错误:重复挂载
const app = createApp(App)
app.mount('#app')
app.mount('#app') // 错误!不能重复挂载
// ✅ 正确:卸载后重新挂载
const app = createApp(App)
const vm = app.mount('#app')
// 如果需要重新挂载,先卸载
app.unmount()
app.mount('#new-app')
// ❌ 错误:挂载到不存在的元素
app.mount('#nonexistent') // 会报错
// ✅ 正确:检查元素是否存在
if (document.getElementById('app')) {
app.mount('#app')
}
.config 对象详解
1. .config 对象的作用
.config 对象用来配置应用的全局行为。
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 配置应用
app.config = {
// 这是错误的!config 是只读的
}
// 正确的配置方式:
app.config.errorHandler = (err, instance, info) => {
console.error('全局错误处理:', err, info)
}
app.config.warnHandler = (msg, instance, trace) => {
console.warn('全局警告处理:', msg, trace)
}
app.config.performance = true // 启用性能追踪
app.mount('#app')
2. .config 的常用配置项
javascript
const app = createApp(App)
// 1. 全局错误处理
app.config.errorHandler = (err, instance, info) => {
// 处理组件渲染错误
console.error('Vue 错误:', err)
// 可以发送错误报告到服务器
// sendErrorToServer(err, info)
}
// 2. 全局警告处理
app.config.warnHandler = (msg, instance, trace) => {
// 处理开发时的警告
console.warn('Vue 警告:', msg)
// 可以在生产环境禁用警告
if (process.env.NODE_ENV === 'production') {
// 不处理警告
}
}
// 3. 性能追踪(开发环境)
app.config.performance = process.env.NODE_ENV !== 'production'
// 4. 全局属性
app.config.globalProperties.$http = axios // 全局 HTTP 客户端
app.config.globalProperties.$filters = { // 全局过滤器
currency(value) {
return '¥' + value.toFixed(2)
}
}
// 5. 编译器选项(仅限完整版)
app.config.compilerOptions = {
isCustomElement: (tag) => tag.startsWith('ion-'),
whitespace: 'condense'
}
3. 实际应用配置示例
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import axios from 'axios'
const app = createApp(App)
// 全局错误处理
app.config.errorHandler = (err, instance, info) => {
console.error('应用错误:', {
error: err,
component: instance?.$options.name || 'Unknown',
info: info
})
// 发送错误到监控服务
if (process.env.NODE_ENV === 'production') {
// sendToErrorTracking(err, info)
}
}
// 全局属性
app.config.globalProperties.$http = axios
app.config.globalProperties.$filters = {
formatDate(date) {
return new Date(date).toLocaleDateString()
},
uppercase(str) {
return str.toUpperCase()
}
}
// 开发环境启用性能追踪
if (process.env.NODE_ENV === 'development') {
app.config.performance = true
}
app.mount('#app')
多应用实例支持
1. 为什么要支持多应用实例?
javascript
// 场景1:同一页面多个独立的 Vue 应用
// index.html
/*
<div id="header-app">头部应用</div>
<div id="main-app">主应用</div>
<div id="sidebar-app">侧边栏应用</div>
<div id="footer-app">底部应用</div>
*/
// main.js
import { createApp } from 'vue'
import HeaderApp from './HeaderApp.vue'
import MainApp from './MainApp.vue'
import SidebarApp from './SidebarApp.vue'
import FooterApp from './FooterApp.vue'
// 创建多个独立的应用实例
const headerApp = createApp(HeaderApp)
const mainApp = createApp(MainApp)
const sidebarApp = createApp(SidebarApp)
const footerApp = createApp(FooterApp)
// 分别挂载到不同的 DOM 元素
headerApp.mount('#header-app')
mainApp.mount('#main-app')
sidebarApp.mount('#sidebar-app')
footerApp.mount('#footer-app')
// 每个应用都有独立的状态、配置和生命周期
2. 多应用实例的实际例子
javascript
// 场景2:微前端架构
// 每个微应用都是独立的 Vue 应用
// user-dashboard.js
import { createApp } from 'vue'
import UserDashboard from './UserDashboard.vue'
const userApp = createApp(UserDashboard)
userApp.config.globalProperties.$apiBase = '/api/user'
userApp.mount('#user-dashboard')
// admin-panel.js
import { createApp } from 'vue'
import AdminPanel from './AdminPanel.vue'
const adminApp = createApp(AdminPanel)
adminApp.config.globalProperties.$apiBase = '/api/admin'
adminApp.mount('#admin-panel')
// 两个应用完全独立,不会相互影响
3. 多应用实例的配置管理
javascript
// app-factory.js - 应用工厂函数
import { createApp } from 'vue'
export function createAppInstance(component, config = {}) {
const app = createApp(component)
// 根据配置设置不同的全局属性
if (config.apiBase) {
app.config.globalProperties.$apiBase = config.apiBase
}
if (config.theme) {
app.config.globalProperties.$theme = config.theme
}
// 设置错误处理
app.config.errorHandler = config.errorHandler || defaultErrorHandler
return app
}
function defaultErrorHandler(err, instance, info) {
console.error('应用错误:', err, info)
}
// 使用工厂函数创建应用
import UserApp from './UserApp.vue'
import AdminApp from './AdminApp.vue'
const userApp = createAppInstance(UserApp, {
apiBase: '/api/user',
theme: 'light',
errorHandler: (err) => {
console.error('用户应用错误:', err)
}
})
const adminApp = createAppInstance(AdminApp, {
apiBase: '/api/admin',
theme: 'dark'
})
userApp.mount('#user-app')
adminApp.mount('#admin-app')
4. 多应用实例的通信
javascript
// event-bus.js - 简单的事件总线
export const EventBus = {
events: {},
on(event, callback) {
if (!this.events[event]) {
this.events[event] = []
}
this.events[event].push(callback)
},
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data))
}
},
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback)
}
}
}
// App1.vue
<script setup>
import { EventBus } from './event-bus.js'
const sendMessage = () => {
EventBus.emit('message', 'Hello from App1!')
}
</script>
// App2.vue
<script setup>
import { onMounted, ref } from 'vue'
import { EventBus } from './event-bus.js'
const message = ref('')
onMounted(() => {
EventBus.on('message', (data) => {
message.value = data
})
})
</script>
完整示例:多应用实例项目
javascript
// main.js
import { createApp } from 'vue'
// 导入不同的根组件
import HeaderApp from './apps/HeaderApp.vue'
import ContentApp from './apps/ContentApp.vue'
import FooterApp from './apps/FooterApp.vue'
// 创建多个应用实例
const apps = []
// 头部应用
const headerApp = createApp(HeaderApp)
headerApp.config.globalProperties.$appName = 'HeaderApp'
headerApp.config.errorHandler = (err) => {
console.error('头部应用错误:', err)
}
apps.push(headerApp)
// 内容应用
const contentApp = createApp(ContentApp)
contentApp.config.globalProperties.$appName = 'ContentApp'
contentApp.config.errorHandler = (err) => {
console.error('内容应用错误:', err)
}
apps.push(contentApp)
// 底部应用
const footerApp = createApp(FooterApp)
footerApp.config.globalProperties.$appName = 'FooterApp'
footerApp.config.errorHandler = (err) => {
console.error('底部应用错误:', err)
}
apps.push(footerApp)
// 挂载所有应用
const mountPoints = [
{ app: headerApp, selector: '#header' },
{ app: contentApp, selector: '#content' },
{ app: footerApp, selector: '#footer' }
]
mountPoints.forEach(({ app, selector }) => {
const element = document.querySelector(selector)
if (element) {
app.mount(element)
console.log(`${app.config.globalProperties.$appName} 已挂载到 ${selector}`)
} else {
console.warn(`挂载点 ${selector} 不存在`)
}
})
总结
核心概念回顾:
- Vue 应用:完整的 Vue 实例,包含组件树和配置
- 根组件:应用的起点组件
- mount():将应用挂载到 DOM 的方法
- .config:应用的全局配置对象
- 多实例:支持创建多个独立的 Vue 应用
关键要点:
- 每个
createApp()
创建独立的应用实例 mount()
只能调用一次(除非先unmount()
).config
用于全局配置和错误处理- 多应用实例适合微前端或复杂页面场景
- 每个应用实例都有独立的状态和生命周期
掌握了这些概念,你就能灵活地创建和管理 Vue3 应用了!