Vue3 应用、组件概念详解 - 初学者完全指南

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} 不存在`)
  }
})

总结

核心概念回顾:

  1. Vue 应用:完整的 Vue 实例,包含组件树和配置
  2. 根组件:应用的起点组件
  3. mount():将应用挂载到 DOM 的方法
  4. .config:应用的全局配置对象
  5. 多实例:支持创建多个独立的 Vue 应用

关键要点:

  • 每个 createApp() 创建独立的应用实例
  • mount() 只能调用一次(除非先 unmount()
  • .config 用于全局配置和错误处理
  • 多应用实例适合微前端或复杂页面场景
  • 每个应用实例都有独立的状态和生命周期

掌握了这些概念,你就能灵活地创建和管理 Vue3 应用了!

相关推荐
武昌库里写JAVA4 分钟前
使用 Java 开发 Android 应用:Kotlin 与 Java 的混合编程
java·vue.js·spring boot·sql·学习
东北南西11 分钟前
设计模式-工厂模式
前端·设计模式
HANK16 分钟前
ECharts高效实现复杂图表指南
前端·vue.js
入秋19 分钟前
Linux服务器安装部署 Nginx、Redis、PostgreSQL、Docker
linux·前端
acocosum21 分钟前
毫米波雷达基础知识学习报告
前端
程序员鱼皮22 分钟前
这套 Java 监控系统太香了!我连夜给项目加上了
java·前端·ai·程序员·开发·软件开发
Juchecar25 分钟前
Vue3 响应式 ref 和 reactive 原理详解及选择建议
前端·vue.js
拾光拾趣录28 分钟前
JavaScript 究竟怎么跑
前端·javascript
zuo-yiran29 分钟前
element table 表格多选框选中高亮
vue.js·elementui
Aotman_30 分钟前
el-input 重写带图标密码框(点击小眼睛显示、隐藏密码)
前端·javascript·vue.js