让我通过实例来说明 TypeScript 如何处理 HTML 元素:

  1. DOM 元素类型
// 基础元素引用
const menuContainer = ref<HTMLDivElement | null>(null)
const priceInput = ref<HTMLInputElement | null>(null)
const foodImage = ref<HTMLImageElement | null>(null)

// 在模板中使用
<template>
    <div ref="menuContainer">
        <input ref="priceInput" type="number" />
        <img ref="foodImage" :src="imageUrl" />
    </div>
</template>
  1. 事件处理
// 事件类型定义
function handleClick(event: MouseEvent): void {
    console.log(event.clientX, event.clientY)
}

function handleInput(event: InputEvent): void {
    const target = event.target as HTMLInputElement
    console.log(target.value)
}

// 在模板中使用
<template>
    <button @click="handleClick">点击</button>
    <input @input="handleInput" />
</template>
  1. 自定义事件
// 定义事件类型
interface OrderEvent {
    orderId: string
    dishes: MenuItem[]
}

// 事件处理函数
function handleOrder(event: OrderEvent): void {
    console.log(`订单 ${event.orderId} 包含 ${event.dishes.length} 个菜品`)
}

// 发出事件
const emit = defineEmits<{
    (event: 'order', payload: OrderEvent): void
    (event: 'cancel'): void
}>()
  1. 表单元素处理
interface FormElements extends HTMLFormControlsCollection {
    username: HTMLInputElement
    password: HTMLInputElement
}

interface OrderForm extends HTMLFormElement {
    readonly elements: FormElements
}

function handleSubmit(event: SubmitEvent) {
    event.preventDefault()
    const form = event.target as OrderForm
    
    const username = form.elements.username.value
    const password = form.elements.password.value
}

// 在模板中使用
<template>
    <form @submit="handleSubmit">
        <input name="username" type="text" />
        <input name="password" type="password" />
        <button type="submit">提交</button>
    </form>
</template>
  1. ref 和 reactive 的类型定义
// ref 的类型定义
const selectedDish = ref<MenuItem | null>(null)
const dishList = ref<MenuItem[]>([])

// reactive 的类型定义
interface State {
    cart: MenuItem[]
    totalPrice: number
    isLoading: boolean
}

const state = reactive<State>({
    cart: [],
    totalPrice: 0,
    isLoading: false
})
  1. 组件 Props 类型定义
// 定义 Props 接口
interface MenuProps {
    category: string
    dishes: MenuItem[]
    isActive?: boolean // 可选属性
}

// 在组件中使用
defineProps<MenuProps>()

// 或者使用 withDefaults
withDefaults(defineProps<MenuProps>(), {
    isActive: false
})
  1. 常见的 HTML 元素事件类型
// 鼠标事件
function handleMouseEvent(event: MouseEvent): void {
    console.log(event.clientX, event.clientY)
}

// 键盘事件
function handleKeyEvent(event: KeyboardEvent): void {
    if (event.key === 'Enter') {
        // 处理回车键
    }
}

// 触摸事件
function handleTouchEvent(event: TouchEvent): void {
    const touch = event.touches[0]
    console.log(touch.clientX, touch.clientY)
}

// 在模板中使用
<template>
    <div 
        @mouseenter="handleMouseEvent"
        @keydown="handleKeyEvent"
        @touchstart="handleTouchEvent"
    >
        交互区域
    </div>
</template>
  1. 自定义组件的 ref 类型
// 定义组件接口
interface MenuComponent {
    reload: () => void
    clear: () => void
}

// 使用组件 ref
const menuRef = ref<MenuComponent | null>(null)

// 调用组件方法
function refreshMenu() {
    menuRef.value?.reload()
}

// 在模板中使用
<template>
    <menu-component ref="menuRef" />
</template>
  1. 错误处理示例
// ❌ 错误示例
const element = document.querySelector('.menu') // 类型推断为 Element | null

// ✅ 正确示例
const element = document.querySelector('.menu') as HTMLDivElement
// 或者
const element = document.querySelector<HTMLDivElement>('.menu')

使用建议:

  1. 总是为 ref 和事件处理函数定义具体类型
  2. 使用 TypeScript 内置的 DOM 类型定义
  3. 避免使用 any 类型
  4. 利用 IDE 的类型提示功能
  5. 合理使用类型断言(as)

这些类型定义可以帮助你:

  • 在开发时捕获潜在错误
  • 提供更好的代码提示
  • 提高代码的可维护性
  • 使代码更加健壮

标签: none

添加新评论

阅读量:205