打造自己的组件库(一)宏函数解析

1. 初始化项目

npm create vite

生成项目后,文件目录如下:

├──  .idea/                    # IntelliJ IDEA 配置目录
├──  .vscode/                  # VS Code 配置目录
├──  public/                   # 静态资源目录
│   └── vite.svg                 # Vite 默认图标
├──  src/                      # 源代码目录
│   ├──  assets/               # 项目资源文件
│   │   └── vue.svg              # Vue 图标
│   ├──  components/           # Vue 组件目录
│   │   └── HelloWorld.vue       # Hello World 组件
│   ├── App.vue                  # 主应用组件
│   ├── main.ts                  # 应用入口文件
│   ├── style.css                # 全局样式文件
│   └── vite-env.d.ts            # Vite 环境类型声明
├── index.html                   # HTML 入口文件
├── package.json                 # 项目配置和依赖管理
├── README.md                    # 项目说明文档
├── tsconfig.json                # TypeScript 基础配置
├── tsconfig.app.json            # TypeScript 应用配置
├── tsconfig.node.json           # TypeScript Node.js 配置
├── vite.config.ts               # Vite 构建工具配置
└── .gitignore                   # Git 忽略文件配置

2. 打造自己的组件,以button为例

Button.vue

<template>
  <button
      ref="_buttonRef"
      class="ms-button"
      :disabled=disabled
      :autofocus=autofocus
      :type=nativeType
      :class="{
        [`ms-button--${type}`]: type,
        [`ms-button--${size}`]: size,
        'is-plain': plain,
        'is-round': round,
        'is-circle': circle,
        'is-disabled': disabled,
      }">
    <slot>slot>
  button>
template>

<script setup lang="ts">
import {type ButtonProps} from "./type";
import {onMounted, ref} from "vue";

const _buttonRef = ref<HTMLButtonElement>();
onMounted(()=>{
  console.log('buttonRef === ', _buttonRef.value)
})
//宏函数
defineOptions({
  name: 'MsButton'
})
withDefaults(defineProps<ButtonProps>(),{
  nativeType: 'button'
})
defineExpose({
  buttonRef: _buttonRef
})
script>

<style scoped>

style>

type.ts

export type ButtonType = 'primary' | 'info' | 'success' | 'warning' | 'danger';
export type ButtonSize = 'large' | 'small';
export type NativeType = 'button' | 'submit' | 'reset'

export interface ButtonProps {
    type?: ButtonType,
    size?: ButtonSize,
    nativeType?: NativeType,
    plain?: boolean,
    round?: boolean,
    circle?: boolean,
    disabled?: boolean,
    autofocus?: boolean,
}

宏函数

在 Vue 3 中,宏函数(Macros) 是特殊的编译时函数,它们在代码被浏览器执行前就被 Vue 编译器处理,主要服务于

编译后效果
转换为标准的 props 组件选项
生成类型安全的 Props 验证代码


2. defineEmits - 声明组件事件

用法

emit('update:title', 'New Title')  // 触发事件

3. defineExpose - 暴露组件公共属性

父组件调用





4. defineOptions (Vue 3.3+) - 设置组件选项


5. defineSlots (Vue 3.3+) - 类型化插槽


三、宏函数 vs 普通函数

特性 宏函数 (如 defineProps) 普通函数 (如 ref)
执行时机 编译阶段处理 运行时执行
代码位置 必须位于

输出 (编译后):

export default {
  setup() {
    const __returned__ = { count: 0 }
    // 编译器注入的暴露逻辑
    Object.assign(__returned__, { 
      __exposed: __returned__ 
    })
    return __returned__
  },
  // 特殊标记
  __expose: true
}

五、最佳实践与注意事项

  1. 避免在逻辑块中使用

    // ❌ 错误!宏不能在函数内使用
    function init() {
      defineProps({ /*...*/ }) 
    }
    
  2. 组合式 API 优先
    宏函数应配合 ref/computed 等组合式 API 使用

  3. 类型声明优先于运行时声明
    使用 TypeScript 时选择类型声明方式:

    // ✅ 推荐
    defineProps<{ title: string }>()
    
    // ⚠️ 次选
    defineProps({ title: String })
    
  4. 与普通函数区分使用

    
    
  5. 版本兼容注意

    • defineOptions/defineSlots 需 Vue 3.3+
    • 旧项目可通过插件 unplugin-vue-define-options 兼容

总结

Vue 3 的宏函数是现代化组件开发的基石,它们:

  • 通过编译时魔法简化组件声明
  • ️ 提供类型安全的 Props/Emits 声明
  • 实现零运行时开销的 API 设计
  • 与组合式 API 协同提升代码组织性

理解宏函数的编译时特性,能帮助开发者更高效地构建健壮且类型安全的 Vue 3 应用。

你可能感兴趣的:(Vue3组件库,vue3组件库,vue.js,javascript,前端)