Skip to content

Vue3 进阶知识点

Vue3 提供了许多高级特性,这些特性可以帮助我们构建更加复杂和高效的应用。本章将介绍一些 Vue3 的进阶知识点。

自定义指令

自定义指令允许我们扩展 Vue 的 DOM 操作能力,实现一些特定的行为。

基本用法

javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// 注册全局自定义指令
app.directive('focus', {
  // 指令挂载到元素时
  mounted(el) {
    el.focus()
  }
})

app.mount('#app')

使用自定义指令

vue
<template>
  <input v-focus placeholder="自动获得焦点">
</template>

指令钩子函数

自定义指令可以定义以下钩子函数:

  • created:指令绑定到元素时调用
  • beforeMount:元素挂载前调用
  • mounted:元素挂载后调用
  • beforeUpdate:元素更新前调用
  • updated:元素更新后调用
  • beforeUnmount:元素卸载前调用
  • unmounted:元素卸载后调用

带参数的自定义指令

javascript
app.directive('color', {
  mounted(el, binding) {
    el.style.color = binding.value
  },
  updated(el, binding) {
    el.style.color = binding.value
  }
})
vue
<template>
  <p v-color="'red'">红色文本</p>
  <p v-color="'blue'">蓝色文本</p>
</template>

Teleport 传送门

Teleport 允许我们将组件的内容渲染到 DOM 树的其他位置,而不是组件的父级 DOM 中。

基本用法

vue
<template>
  <div class="modal-wrapper">
    <button @click="showModal = true">打开模态框</button>
    
    <Teleport to="body">
      <div v-if="showModal" class="modal">
        <div class="modal-content">
          <h2>模态框</h2>
          <p>这是一个使用 Teleport 的模态框</p>
          <button @click="showModal = false">关闭</button>
        </div>
      </div>
    </Teleport>
  </div>
</template>

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

const showModal = ref(false)
</script>

<style scoped>
.modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal-content {
  background-color: white;
  padding: 20px;
  border-radius: 4px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
</style>

Suspense 异步组件

Suspense 允许我们在等待异步组件加载时显示一个占位内容。

基本用法

vue
<!-- AsyncComponent.vue -->
<template>
  <div>
    <h2>异步组件</h2>
    <p>{{ data }}</p>
  </div>
</template>

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

const data = ref('加载中...')

// 模拟异步加载
onMounted(async () => {
  await new Promise(resolve => setTimeout(resolve, 1000))
  data.value = '异步加载完成'
})
</script>
vue
<!-- ParentComponent.vue -->
<template>
  <div>
    <h1>父组件</h1>
    <Suspense>
      <template #default>
        <AsyncComponent />
      </template>
      <template #fallback>
        <div>加载中...</div>
      </template>
    </Suspense>
  </div>
</template>

<script setup>
import AsyncComponent from './AsyncComponent.vue'
</script>

动态组件 & keep-alive

动态组件

动态组件允许我们根据条件渲染不同的组件。

vue
<template>
  <div>
    <button @click="currentComponent = 'ComponentA'">显示组件 A</button>
    <button @click="currentComponent = 'ComponentB'">显示组件 B</button>
    
    <component :is="currentComponent" />
  </div>
</template>

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

const currentComponent = ref('ComponentA')
</script>

keep-alive

keep-alive 可以缓存组件的状态,避免组件被频繁销毁和重建。

vue
<template>
  <div>
    <button @click="currentComponent = 'ComponentA'">显示组件 A</button>
    <button @click="currentComponent = 'ComponentB'">显示组件 B</button>
    
    <keep-alive>
      <component :is="currentComponent" />
    </keep-alive>
  </div>
</template>

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

const currentComponent = ref('ComponentA')
</script>

模块化与组件拆分规范

组件拆分原则

  1. 单一职责:每个组件只负责一个功能
  2. 可复用性:设计可复用的组件
  3. 可维护性:代码结构清晰,易于理解和维护
  4. 性能优化:避免不必要的渲染和计算

目录结构示例

src/
├── components/
│   ├── common/          # 通用组件
│   │   ├── Button.vue
│   │   ├── Input.vue
│   │   └── Modal.vue
│   ├── layout/          # 布局组件
│   │   ├── Header.vue
│   │   ├── Footer.vue
│   │   └── Sidebar.vue
│   └── business/        # 业务组件
│       ├── UserCard.vue
│       ├── ProductList.vue
│       └── OrderForm.vue
├── views/               # 页面组件
│   ├── Home.vue
│   ├── About.vue
│   └── User.vue
├── utils/               # 工具函数
├── api/                 # API 调用
└── stores/              # 状态管理

实战示例

自定义指令:点击外部关闭

javascript
// directives/clickOutside.js
export default {
  mounted(el, binding) {
    el._clickOutsideHandler = (event) => {
      if (!(el === event.target || el.contains(event.target))) {
        binding.value(event)
      }
    }
    document.addEventListener('click', el._clickOutsideHandler)
  },
  unmounted(el) {
    document.removeEventListener('click', el._clickOutsideHandler)
  }
}

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import clickOutside from './directives/clickOutside'

const app = createApp(App)
app.directive('click-outside', clickOutside)
app.mount('#app')
vue
<template>
  <div>
    <button @click="showDropdown = !showDropdown">显示下拉菜单</button>
    
    <div v-if="showDropdown" v-click-outside="() => showDropdown = false" class="dropdown">
      <p>下拉菜单项 1</p>
      <p>下拉菜单项 2</p>
      <p>下拉菜单项 3</p>
    </div>
  </div>
</template>

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

const showDropdown = ref(false)
</script>

<style scoped>
.dropdown {
  position: absolute;
  background-color: white;
  border: 1px solid #ccc;
  padding: 10px;
  border-radius: 4px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
</style>

Teleport 实现通知组件

vue
<template>
  <div>
    <button @click="showNotification('成功', '操作成功!')">显示成功通知</button>
    <button @click="showNotification('错误', '操作失败!')">显示错误通知</button>
    
    <Teleport to="body">
      <div v-for="notification in notifications" :key="notification.id" class="notification" :class="notification.type">
        <h3>{{ notification.title }}</h3>
        <p>{{ notification.message }}</p>
        <button @click="removeNotification(notification.id)">&times;</button>
      </div>
    </Teleport>
  </div>
</template>

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

const notifications = ref([])
let id = 0

function showNotification(type, message) {
  const notification = {
    id: ++id,
    type,
    title: type === '成功' ? '成功' : '错误',
    message
  }
  
  notifications.value.push(notification)
  
  // 3秒后自动移除
  setTimeout(() => {
    removeNotification(notification.id)
  }, 3000)
}

function removeNotification(id) {
  notifications.value = notifications.value.filter(n => n.id !== id)
}
</script>

<style scoped>
.notification {
  position: fixed;
  top: 20px;
  right: 20px;
  padding: 15px;
  border-radius: 4px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  z-index: 1000;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  min-width: 300px;
}

.notification.success {
  background-color: #d4edda;
  color: #155724;
  border: 1px solid #c3e6cb;
}

.notification.error {
  background-color: #f8d7da;
  color: #721c24;
  border: 1px solid #f5c6cb;
}

.notification button {
  background: none;
  border: none;
  font-size: 18px;
  cursor: pointer;
  margin-left: 10px;
}
</style>

通过本章的学习,我们掌握了 Vue3 的一些进阶知识点,包括自定义指令、Teleport 传送门、Suspense 异步组件、动态组件与 keep-alive,以及模块化与组件拆分规范等。这些特性可以帮助我们构建更加复杂和高效的 Vue 应用,提升开发效率和代码质量。

© 2026 编程马·菜鸟教程 版权所有