技术文档中心
首页
React
Vue
TypeScript
Kotlin
React Native
Electron
Android
首页
React
Vue
TypeScript
Kotlin
React Native
Electron
Android
  • Vue2 基础

    • Vue 学习指南
    • Vue2 快速入门
    • Vue2 模板语法
    • Vue2 组件基础
    • Vue2 计算属性与侦听器
    • Vue2 生命周期
  • Vue2 进阶

    • Vue2 组件通信
    • Vue2 插槽详解
    • Vue2 混入与自定义指令
    • Vue2 过渡与动画
    • Vuex 状态管理
  • Vue2 高级

    • Vue2 性能优化
    • Vue2 服务端渲染(SSR)
    • Vue2 源码解析
  • Vue3 基础

    • Vue3 快速入门
    • Vue3 Composition API
    • Vue3 响应式系统
    • Vue3 组件基础
    • Vue3 生命周期
  • Vue3 进阶

    • Vue3 组合式函数
    • Vue3 组件通信
    • Vue3 Teleport 与 Suspense
    • Pinia 状态管理
    • Vue Router 4
  • Vue3 高级

    • Vue3 TypeScript
    • Vue3 性能优化
    • Vue3 测试
    • Vue3 SSR
    • Vue3 源码解析
  • 实战项目

    • Vue2 实战项目
    • Vue3 实战项目
    • Vue2 迁移 Vue3

Vue3 组件基础

组件定义

Options API

<script>
export default {
  name: 'MyComponent',
  props: {
    title: String
  },
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>

Composition API

<script setup>
import { ref } from 'vue'

defineProps({
  title: String
})

const count = ref(0)
const increment = () => count.value++
</script>

Props

基本用法

<script setup>
const props = defineProps({
  title: String,
  likes: Number,
  isPublished: Boolean
})

console.log(props.title)
</script>

Props 验证

<script setup>
defineProps({
  propA: Number,
  propB: [String, Number],
  propC: {
    type: String,
    required: true
  },
  propD: {
    type: Number,
    default: 100
  },
  propE: {
    type: Object,
    default: () => ({ message: 'hello' })
  },
  propF: {
    validator: (value) => {
      return ['success', 'warning', 'danger'].includes(value)
    }
  }
})
</script>

Props 解构

<script setup>
const { title, likes = 0 } = defineProps(['title', 'likes'])
</script>

Emits

基本用法

<script setup>
const emit = defineEmits(['update', 'delete'])

const handleClick = () => {
  emit('update', { id: 1 })
}
</script>

Emits 验证

<script setup>
const emit = defineEmits({
  submit: (payload) => {
    if (payload.email && payload.password) {
      return true
    } else {
      console.warn('Invalid submit event payload!')
      return false
    }
  }
})

const submitForm = () => {
  emit('submit', { email: 'test@example.com', password: '123456' })
}
</script>

插槽

默认插槽

<!-- 子组件 -->
<template>
  <div class="container">
    <slot>默认内容</slot>
  </div>
</template>

<!-- 父组件 -->
<MyComponent>
  <p>插槽内容</p>
</MyComponent>

具名插槽

<!-- 子组件 -->
<template>
  <div class="container">
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<!-- 父组件 -->
<BaseLayout>
  <template #header>
    <h1>标题</h1>
  </template>
  
  <p>主要内容</p>
  
  <template #footer>
    <p>底部信息</p>
  </template>
</BaseLayout>

作用域插槽

<!-- 子组件 -->
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <slot :item="item"></slot>
    </li>
  </ul>
</template>

<!-- 父组件 -->
<MyList :items="items">
  <template #default="{ item }">
    <span>{{ item.name }}</span>
  </template>
</MyList>

动态组件

<template>
  <component :is="currentComponent"></component>
</template>

<script setup>
import { ref } from 'vue'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'

const currentComponent = ref(ComponentA)
</script>

KeepAlive

<template>
  <KeepAlive :include="['ComponentA', 'ComponentB']">
    <component :is="currentComponent"></component>
  </KeepAlive>
</template>

异步组件

import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
)

// 带选项
const AsyncCompWithOptions = defineAsyncComponent({
  loader: () => import('./components/MyComponent.vue'),
  loadingComponent: LoadingComponent,
  errorComponent: ErrorComponent,
  delay: 200,
  timeout: 3000
})
最近更新: 2026/1/27 15:51
Contributors: hailong
Prev
Vue3 响应式系统
Next
Vue3 生命周期