考察点分析

核心能力维度

  1. 组合式API应用:考察逻辑复用能力与响应式状态管理

  2. Teleport机制理解:评估对DOM挂载位置与样式作用域的掌握

  3. 可访问性实践:验证键盘交互与焦点管理的规范化实现

  4. 动画集成方案:测试过渡动画与组件生命周期的协调能力

技术评估点

  • Teleport的DOM挂载策略及其对CSS层叠上下文的影响
  • 组合式API中状态管理与组件通信的合理抽象
  • 事件监听的绑定/解绑与内存泄漏防范
  • 符合WAI-ARIA标准的焦点控制实现
  • CSS Transition与组件挂载/卸载时序的协同

技术解析

关键知识点

Teleport > Composition API > Focus Trap > Keyboard Events > CSS Transition

原理剖析

  1. Teleport机制:将模态框渲染至<body>末端,避免父组件position: relative导致的定位失效。通过to属性指定目标容器,保持全局样式稳定性

  2. 响应式控制:使用ref管理开闭状态,通过defineEmits暴露open/close事件。采用v-model语法糖实现双向绑定

  3. 事件管理:组件挂载时注册keydown监听,处理ESC关闭。卸载时通过removeEventListener防止内存泄漏。使用tabindex="-1"focus-trap库实现焦点锁定

  4. 动画集成<Transition>组件配合enter-active-class实现入场/离场动画。注意duration属性与CSS动画时间的同步,防止DOM提前卸载

常见误区

  • 未在onUnmounted清除事件监听导致内存泄漏
  • 直接修改props违反单向数据流原则
  • 使用setTimeout处理动画导致时序错乱
  • 忽略role="dialog"等ARIA属性影响可访问性

问题解答

实现步骤如下:

  1. Teleport挂载:将模态框内容传送至body末端,避免CSS层级问题
  2. 组合式状态:使用ref控制显隐状态,通过defineEmits触发状态变更
  3. 键盘监听:在onMounted注册ESC键监听,onUnmounted移除
  4. 焦点管理:使用autofocus属性与focus-trap-vue库实现焦点锁定
  5. 动画过渡<Transition>包裹模态内容,配置enter-active等动画类

解决方案

  // Modal.vue
<template>
  <Teleport :to="target">
    <Transition name="modal" @after-leave="$emit('close')">
      <div v-if="isOpen" 
           role="dialog"
           class="modal-wrap"
           @keydown.esc="handleClose">
        <div class="modal-content">
          <slot />
        </div>
      </div>
    </Transition>
  </Teleport>
</template>

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

const props = defineProps({
  modelValue: Boolean,
  target: { type: String, default: 'body' }
})
const emit = defineEmits(['update:modelValue'])

const isOpen = ref(false)

// 控制显隐同步
watch(() => props.modelValue, val => isOpen.value = val)
watch(isOpen, val => emit('update:modelValue', val))

// ESC关闭处理
const handleClose = () => isOpen.value = false

// 键盘监听
const keyHandler = (e) => {
  if (e.key === 'Escape') handleClose()
}

onMounted(() => window.addEventListener('keydown', keyHandler))
onUnmounted(() => window.removeEventListener('keydown', keyHandler))
</script>

<style>
.modal-enter-active, .modal-leave-active {
  transition: opacity 0.3s ease;
}
.modal-enter-from, .modal-leave-to {
  opacity: 0;
}
</style>
  

可扩展性建议

  1. 动态挂载点:通过targetprop支持自定义挂载容器
  2. 动画增强:集成animate.css实现多样化过渡效果
  3. 全局状态:结合Pinia管理多模态框的叠加状态
  4. 性能优化:添加lazy修饰符实现按需加载模态内容

深度追问

追问1:如何实现点击外部关闭?

提示:使用@click.self判断点击区域

追问2:如何处理多个模态框叠加?

提示:采用Z-index堆栈管理与暂停背景滚动

追问3:如何保证组件SSR兼容?

提示:在生命周期中判断window对象存在性

Last updated 06 Mar 2025, 13:07 +0800 . history